memorix 1.9.2 → 1.9.4
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 +27 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/cli/index.js +358 -146
- package/dist/index.js +281 -125
- package/dist/maintenance-runner.js +219 -97
- package/dist/media-audio-runner.js +219 -97
- package/dist/media-video-runner.js +219 -97
- package/dist/memcode-runtime/CHANGELOG.md +27 -0
- package/dist/sdk.js +280 -124
- package/dist/vector-backfill-runner.js +219 -97
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +15 -0
- package/docs/ARCHITECTURE.md +23 -0
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/PERFORMANCE.md +50 -0
- package/docs/README.md +1 -1
- package/package.json +1 -1
- package/plugins/antigravity/memorix/plugin.json +1 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/hermes/memorix/plugin.yaml +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/commands/doctor.ts +78 -17
- package/src/cli/commands/media.ts +2 -0
- package/src/media/minimax.ts +26 -2
- package/src/media/video-jobs.ts +9 -1
- package/src/server.ts +3 -1
- package/src/store/mini-skill-store.ts +31 -22
- package/src/store/obs-store.ts +46 -30
- package/src/store/session-store.ts +35 -21
- package/src/store/sqlite-db.ts +16 -7
- package/src/store/sqlite-reliability.ts +87 -0
- package/src/store/sqlite-store.ts +4 -1
package/dist/sdk.js
CHANGED
|
@@ -468,70 +468,79 @@ function getDatabase(dataDir) {
|
|
|
468
468
|
loadBetterSqlite3();
|
|
469
469
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
470
470
|
const dbPath = path3.join(dataDir, "memorix.db");
|
|
471
|
-
|
|
472
|
-
db2.pragma("journal_mode = WAL");
|
|
473
|
-
db2.pragma("busy_timeout = 5000");
|
|
474
|
-
db2.pragma("foreign_keys = ON");
|
|
475
|
-
db2.exec(CREATE_OBSERVATIONS_TABLE);
|
|
476
|
-
db2.exec(CREATE_MINI_SKILLS_TABLE);
|
|
477
|
-
db2.exec(CREATE_SESSIONS_TABLE);
|
|
478
|
-
db2.exec(CREATE_META_TABLE);
|
|
479
|
-
db2.exec(CREATE_TEAM_AGENTS_TABLE);
|
|
480
|
-
db2.exec(CREATE_TEAM_TASKS_TABLE);
|
|
481
|
-
db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
|
|
482
|
-
db2.exec(CREATE_TEAM_MESSAGES_TABLE);
|
|
483
|
-
db2.exec(CREATE_TEAM_LOCKS_TABLE);
|
|
484
|
-
db2.exec(CREATE_TEAM_ROLES_TABLE);
|
|
485
|
-
db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
|
|
486
|
-
db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
|
|
487
|
-
db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
|
|
488
|
-
db2.exec(CREATE_CODE_FILES_TABLE);
|
|
489
|
-
db2.exec(CREATE_CODE_SYMBOLS_TABLE);
|
|
490
|
-
db2.exec(CREATE_CODE_EDGES_TABLE);
|
|
491
|
-
db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
|
|
492
|
-
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
493
|
-
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
494
|
-
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
471
|
+
let db2;
|
|
495
472
|
try {
|
|
496
|
-
db2
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
db2.exec(
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
db2.exec(
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
db2.exec(
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
db2.exec(
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
db2.exec(
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
473
|
+
db2 = createDatabase(dbPath);
|
|
474
|
+
db2.pragma("busy_timeout = 5000");
|
|
475
|
+
db2.pragma("journal_mode = WAL");
|
|
476
|
+
db2.pragma("foreign_keys = ON");
|
|
477
|
+
db2.exec(CREATE_OBSERVATIONS_TABLE);
|
|
478
|
+
db2.exec(CREATE_MINI_SKILLS_TABLE);
|
|
479
|
+
db2.exec(CREATE_SESSIONS_TABLE);
|
|
480
|
+
db2.exec(CREATE_META_TABLE);
|
|
481
|
+
db2.exec(CREATE_TEAM_AGENTS_TABLE);
|
|
482
|
+
db2.exec(CREATE_TEAM_TASKS_TABLE);
|
|
483
|
+
db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
|
|
484
|
+
db2.exec(CREATE_TEAM_MESSAGES_TABLE);
|
|
485
|
+
db2.exec(CREATE_TEAM_LOCKS_TABLE);
|
|
486
|
+
db2.exec(CREATE_TEAM_ROLES_TABLE);
|
|
487
|
+
db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
|
|
488
|
+
db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
|
|
489
|
+
db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
|
|
490
|
+
db2.exec(CREATE_CODE_FILES_TABLE);
|
|
491
|
+
db2.exec(CREATE_CODE_SYMBOLS_TABLE);
|
|
492
|
+
db2.exec(CREATE_CODE_EDGES_TABLE);
|
|
493
|
+
db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
|
|
494
|
+
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
495
|
+
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
496
|
+
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
497
|
+
try {
|
|
498
|
+
db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
|
|
499
|
+
} catch {
|
|
500
|
+
}
|
|
501
|
+
try {
|
|
502
|
+
db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
|
|
503
|
+
} catch {
|
|
504
|
+
}
|
|
505
|
+
try {
|
|
506
|
+
db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
|
|
507
|
+
} catch {
|
|
508
|
+
}
|
|
509
|
+
try {
|
|
510
|
+
db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
|
|
511
|
+
} catch {
|
|
512
|
+
}
|
|
513
|
+
try {
|
|
514
|
+
db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
|
|
515
|
+
} catch {
|
|
516
|
+
}
|
|
517
|
+
try {
|
|
518
|
+
db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
|
|
519
|
+
} catch {
|
|
520
|
+
}
|
|
521
|
+
try {
|
|
522
|
+
db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
|
|
523
|
+
} catch {
|
|
524
|
+
}
|
|
525
|
+
try {
|
|
526
|
+
db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
|
|
527
|
+
} catch {
|
|
528
|
+
}
|
|
529
|
+
applySchemaMigrations(db2);
|
|
530
|
+
db2.exec(CREATE_INDEXES);
|
|
531
|
+
initializeObservationLexicalIndex(db2);
|
|
532
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
533
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
534
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
535
|
+
_dbCache.set(normalized, db2);
|
|
536
|
+
return db2;
|
|
537
|
+
} catch (error) {
|
|
538
|
+
try {
|
|
539
|
+
db2?.close();
|
|
540
|
+
} catch {
|
|
541
|
+
}
|
|
542
|
+
throw error;
|
|
526
543
|
}
|
|
527
|
-
applySchemaMigrations(db2);
|
|
528
|
-
db2.exec(CREATE_INDEXES);
|
|
529
|
-
initializeObservationLexicalIndex(db2);
|
|
530
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
531
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
532
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
533
|
-
_dbCache.set(normalized, db2);
|
|
534
|
-
return db2;
|
|
535
544
|
}
|
|
536
545
|
function closeDatabase(dataDir) {
|
|
537
546
|
const normalized = path3.resolve(dataDir);
|
|
@@ -2369,6 +2378,74 @@ var init_types = __esm({
|
|
|
2369
2378
|
}
|
|
2370
2379
|
});
|
|
2371
2380
|
|
|
2381
|
+
// src/store/sqlite-reliability.ts
|
|
2382
|
+
function isTransientSqliteError(error) {
|
|
2383
|
+
const code = error?.code;
|
|
2384
|
+
if (typeof code === "string") {
|
|
2385
|
+
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
2386
|
+
}
|
|
2387
|
+
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
2388
|
+
}
|
|
2389
|
+
function isSqliteUnavailableError(error) {
|
|
2390
|
+
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
2391
|
+
}
|
|
2392
|
+
function degradedReadError(storeName) {
|
|
2393
|
+
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
2394
|
+
}
|
|
2395
|
+
function degradedWriteError(storeName) {
|
|
2396
|
+
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
2397
|
+
}
|
|
2398
|
+
function formatSqliteFailure(error) {
|
|
2399
|
+
return error instanceof Error && error.message ? error.message : String(error);
|
|
2400
|
+
}
|
|
2401
|
+
function delay(ms) {
|
|
2402
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
2403
|
+
}
|
|
2404
|
+
async function retrySqliteBusy(operation, label) {
|
|
2405
|
+
for (let attempt = 0; ; attempt++) {
|
|
2406
|
+
try {
|
|
2407
|
+
return await operation();
|
|
2408
|
+
} catch (error) {
|
|
2409
|
+
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
2410
|
+
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
2411
|
+
console.error(
|
|
2412
|
+
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
2413
|
+
);
|
|
2414
|
+
await delay(waitMs);
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
async function initializeSqliteStore(factory, dataDir, label) {
|
|
2419
|
+
try {
|
|
2420
|
+
loadBetterSqlite3();
|
|
2421
|
+
} catch (error) {
|
|
2422
|
+
throw new SqliteUnavailableError(error);
|
|
2423
|
+
}
|
|
2424
|
+
return retrySqliteBusy(async () => {
|
|
2425
|
+
const store = factory();
|
|
2426
|
+
await store.init(dataDir);
|
|
2427
|
+
return store;
|
|
2428
|
+
}, label);
|
|
2429
|
+
}
|
|
2430
|
+
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
2431
|
+
var init_sqlite_reliability = __esm({
|
|
2432
|
+
"src/store/sqlite-reliability.ts"() {
|
|
2433
|
+
"use strict";
|
|
2434
|
+
init_esm_shims();
|
|
2435
|
+
init_sqlite_db();
|
|
2436
|
+
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
2437
|
+
SqliteUnavailableError = class extends Error {
|
|
2438
|
+
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
2439
|
+
constructor(cause) {
|
|
2440
|
+
super(
|
|
2441
|
+
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
2442
|
+
);
|
|
2443
|
+
this.name = "SqliteUnavailableError";
|
|
2444
|
+
}
|
|
2445
|
+
};
|
|
2446
|
+
}
|
|
2447
|
+
});
|
|
2448
|
+
|
|
2372
2449
|
// src/store/mini-skill-store.ts
|
|
2373
2450
|
var mini_skill_store_exports = {};
|
|
2374
2451
|
__export(mini_skill_store_exports, {
|
|
@@ -2440,16 +2517,18 @@ async function initMiniSkillStore(dataDir) {
|
|
|
2440
2517
|
if (_store && _storeDataDir === dataDir) return _store;
|
|
2441
2518
|
_store = null;
|
|
2442
2519
|
_storeDataDir = null;
|
|
2520
|
+
let degradedReason = "SQLite runtime unavailable";
|
|
2443
2521
|
try {
|
|
2444
|
-
const store2 = new MiniSkillSqliteStore();
|
|
2445
|
-
await store2.init(dataDir);
|
|
2522
|
+
const store2 = await initializeSqliteStore(() => new MiniSkillSqliteStore(), dataDir, "Mini-skill store");
|
|
2446
2523
|
_store = store2;
|
|
2447
2524
|
_storeDataDir = dataDir;
|
|
2448
2525
|
return store2;
|
|
2449
2526
|
} catch (err) {
|
|
2450
|
-
|
|
2527
|
+
if (!isSqliteUnavailableError(err)) throw err;
|
|
2528
|
+
degradedReason = err instanceof Error ? err.message : String(err);
|
|
2529
|
+
console.error(`[memorix] MiniSkillSqliteStore unavailable, running in degraded read-only mode: ${degradedReason}`);
|
|
2451
2530
|
}
|
|
2452
|
-
const store = new MiniSkillGracefulDegrade();
|
|
2531
|
+
const store = new MiniSkillGracefulDegrade(degradedReason);
|
|
2453
2532
|
await store.init(dataDir);
|
|
2454
2533
|
_store = store;
|
|
2455
2534
|
_storeDataDir = dataDir;
|
|
@@ -2461,6 +2540,7 @@ var init_mini_skill_store = __esm({
|
|
|
2461
2540
|
"use strict";
|
|
2462
2541
|
init_esm_shims();
|
|
2463
2542
|
init_sqlite_db();
|
|
2543
|
+
init_sqlite_reliability();
|
|
2464
2544
|
MiniSkillSqliteStore = class {
|
|
2465
2545
|
db = null;
|
|
2466
2546
|
dataDir = "";
|
|
@@ -2569,7 +2649,7 @@ var init_mini_skill_store = __esm({
|
|
|
2569
2649
|
* SQLite serializes write transactions, so concurrent calls are safely sequenced.
|
|
2570
2650
|
*/
|
|
2571
2651
|
async atomicInsertWithId(skillWithoutId) {
|
|
2572
|
-
|
|
2652
|
+
return retrySqliteBusy(async () => this.db.transaction(() => {
|
|
2573
2653
|
const row = this.stmtGetMeta.get("mini_skills_next_id");
|
|
2574
2654
|
const nextId2 = row ? parseInt(row.value, 10) : 1;
|
|
2575
2655
|
const skill2 = { ...skillWithoutId, id: nextId2 };
|
|
@@ -2578,8 +2658,7 @@ var init_mini_skill_store = __esm({
|
|
|
2578
2658
|
this.stmtBumpGeneration.run();
|
|
2579
2659
|
this.knownGeneration = this.readGeneration();
|
|
2580
2660
|
return skill2;
|
|
2581
|
-
})();
|
|
2582
|
-
return result;
|
|
2661
|
+
})(), "Mini-skill promotion");
|
|
2583
2662
|
}
|
|
2584
2663
|
// ── Freshness ────────────────────────────────────────────────────
|
|
2585
2664
|
async ensureFresh() {
|
|
@@ -2598,10 +2677,17 @@ var init_mini_skill_store = __esm({
|
|
|
2598
2677
|
}
|
|
2599
2678
|
};
|
|
2600
2679
|
MiniSkillGracefulDegrade = class {
|
|
2680
|
+
constructor(reason = "SQLite runtime unavailable") {
|
|
2681
|
+
this.reason = reason;
|
|
2682
|
+
}
|
|
2683
|
+
reason;
|
|
2601
2684
|
warned = false;
|
|
2685
|
+
unavailableRead() {
|
|
2686
|
+
return degradedReadError("mini-skills");
|
|
2687
|
+
}
|
|
2602
2688
|
warn() {
|
|
2603
2689
|
if (!this.warned) {
|
|
2604
|
-
console.error("[memorix] MiniSkillStore: SQLite unavailable \u2014 mini-skills
|
|
2690
|
+
console.error("[memorix] MiniSkillStore: SQLite unavailable \u2014 mini-skills cannot be read or written. Install a supported SQLite runtime.");
|
|
2605
2691
|
this.warned = true;
|
|
2606
2692
|
}
|
|
2607
2693
|
}
|
|
@@ -2609,28 +2695,33 @@ var init_mini_skill_store = __esm({
|
|
|
2609
2695
|
this.warn();
|
|
2610
2696
|
}
|
|
2611
2697
|
async loadAll() {
|
|
2612
|
-
|
|
2698
|
+
throw this.unavailableRead();
|
|
2613
2699
|
}
|
|
2614
2700
|
async loadByProject(_projectId) {
|
|
2615
|
-
|
|
2701
|
+
throw this.unavailableRead();
|
|
2616
2702
|
}
|
|
2617
2703
|
async loadIdCounter() {
|
|
2618
|
-
|
|
2704
|
+
throw this.unavailableRead();
|
|
2619
2705
|
}
|
|
2620
2706
|
async insert(_skill) {
|
|
2621
2707
|
this.warn();
|
|
2708
|
+
throw degradedWriteError("mini-skills");
|
|
2622
2709
|
}
|
|
2623
2710
|
async update(_skill) {
|
|
2624
2711
|
this.warn();
|
|
2712
|
+
throw degradedWriteError("mini-skills");
|
|
2625
2713
|
}
|
|
2626
2714
|
async remove(_id) {
|
|
2627
2715
|
this.warn();
|
|
2716
|
+
throw degradedWriteError("mini-skills");
|
|
2628
2717
|
}
|
|
2629
2718
|
async saveIdCounter(_nextId) {
|
|
2719
|
+
this.warn();
|
|
2720
|
+
throw degradedWriteError("mini-skills");
|
|
2630
2721
|
}
|
|
2631
2722
|
async atomicInsertWithId(skillWithoutId) {
|
|
2632
2723
|
this.warn();
|
|
2633
|
-
|
|
2724
|
+
throw degradedWriteError("mini-skills");
|
|
2634
2725
|
}
|
|
2635
2726
|
async ensureFresh() {
|
|
2636
2727
|
return false;
|
|
@@ -2641,6 +2732,9 @@ var init_mini_skill_store = __esm({
|
|
|
2641
2732
|
getBackendName() {
|
|
2642
2733
|
return "degraded";
|
|
2643
2734
|
}
|
|
2735
|
+
getBackendReason() {
|
|
2736
|
+
return this.reason;
|
|
2737
|
+
}
|
|
2644
2738
|
};
|
|
2645
2739
|
_store = null;
|
|
2646
2740
|
_storeDataDir = null;
|
|
@@ -4843,10 +4937,10 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
|
|
|
4843
4937
|
);
|
|
4844
4938
|
}
|
|
4845
4939
|
if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
|
|
4846
|
-
const
|
|
4940
|
+
const delay3 = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
4847
4941
|
const retryAfter = response.headers.get("retry-after");
|
|
4848
4942
|
const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
|
|
4849
|
-
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter :
|
|
4943
|
+
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay3;
|
|
4850
4944
|
console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
|
|
4851
4945
|
await waitForRetry(waitMs, options.signal);
|
|
4852
4946
|
return fetchWithRetry(url, apiKey, body, options, attempt + 1, nativeGemini);
|
|
@@ -6878,6 +6972,7 @@ var init_sqlite_store = __esm({
|
|
|
6878
6972
|
"use strict";
|
|
6879
6973
|
init_esm_shims();
|
|
6880
6974
|
init_sqlite_db();
|
|
6975
|
+
init_sqlite_reliability();
|
|
6881
6976
|
init_sqlite_fts();
|
|
6882
6977
|
SqliteBackend = class {
|
|
6883
6978
|
db = null;
|
|
@@ -7155,7 +7250,9 @@ var init_sqlite_store = __esm({
|
|
|
7155
7250
|
// ── Compound atomic operation ────────────────────────────────────
|
|
7156
7251
|
async atomic(fn) {
|
|
7157
7252
|
const run = this._atomicQueue.catch(() => void 0).then(async () => {
|
|
7158
|
-
|
|
7253
|
+
await retrySqliteBusy(async () => {
|
|
7254
|
+
this.db.prepare("BEGIN IMMEDIATE").run();
|
|
7255
|
+
}, "Observation atomic write");
|
|
7159
7256
|
try {
|
|
7160
7257
|
const tx = {
|
|
7161
7258
|
loadAll: async () => this.rawLoadAll(),
|
|
@@ -7254,15 +7351,15 @@ function resetObservationStore() {
|
|
|
7254
7351
|
async function createObservationStore(dataDir) {
|
|
7255
7352
|
try {
|
|
7256
7353
|
const { SqliteBackend: SqliteBackend2 } = await Promise.resolve().then(() => (init_sqlite_store(), sqlite_store_exports));
|
|
7257
|
-
|
|
7258
|
-
await store2.init(dataDir);
|
|
7259
|
-
return store2;
|
|
7354
|
+
return await initializeSqliteStore(() => new SqliteBackend2(), dataDir, "Observation store");
|
|
7260
7355
|
} catch (err) {
|
|
7261
|
-
|
|
7356
|
+
if (!isSqliteUnavailableError(err)) throw err;
|
|
7357
|
+
const reason = formatSqliteFailure(err);
|
|
7358
|
+
console.error(`[memorix] SQLite module unavailable \u2014 degraded mode (reads/writes disabled): ${reason}`);
|
|
7359
|
+
const degraded = new DegradedBackend(reason);
|
|
7360
|
+
await degraded.init(dataDir);
|
|
7361
|
+
return degraded;
|
|
7262
7362
|
}
|
|
7263
|
-
const store = new DegradedBackend();
|
|
7264
|
-
await store.init(dataDir);
|
|
7265
|
-
return store;
|
|
7266
7363
|
}
|
|
7267
7364
|
async function initObservationStore(dataDir) {
|
|
7268
7365
|
if (_store2 && _storeDataDir2 === dataDir) {
|
|
@@ -7286,36 +7383,44 @@ var init_obs_store = __esm({
|
|
|
7286
7383
|
"src/store/obs-store.ts"() {
|
|
7287
7384
|
"use strict";
|
|
7288
7385
|
init_esm_shims();
|
|
7386
|
+
init_sqlite_reliability();
|
|
7289
7387
|
_store2 = null;
|
|
7290
7388
|
_storeDataDir2 = null;
|
|
7291
7389
|
DegradedBackend = class {
|
|
7390
|
+
constructor(reason = "SQLite runtime unavailable") {
|
|
7391
|
+
this.reason = reason;
|
|
7392
|
+
}
|
|
7393
|
+
reason;
|
|
7292
7394
|
dataDir = "";
|
|
7395
|
+
unavailableRead() {
|
|
7396
|
+
return degradedReadError("observations");
|
|
7397
|
+
}
|
|
7293
7398
|
async init(dataDir) {
|
|
7294
7399
|
this.dataDir = dataDir;
|
|
7295
7400
|
}
|
|
7296
7401
|
async loadAll() {
|
|
7297
|
-
|
|
7402
|
+
throw this.unavailableRead();
|
|
7298
7403
|
}
|
|
7299
7404
|
async loadByProject(_projectId, _options) {
|
|
7300
|
-
|
|
7405
|
+
throw this.unavailableRead();
|
|
7301
7406
|
}
|
|
7302
7407
|
async countByProject(_projectId, _options) {
|
|
7303
|
-
|
|
7408
|
+
throw this.unavailableRead();
|
|
7304
7409
|
}
|
|
7305
7410
|
async getById(_id) {
|
|
7306
|
-
|
|
7411
|
+
throw this.unavailableRead();
|
|
7307
7412
|
}
|
|
7308
7413
|
async loadIdCounter() {
|
|
7309
|
-
|
|
7414
|
+
throw this.unavailableRead();
|
|
7310
7415
|
}
|
|
7311
7416
|
async countAll() {
|
|
7312
|
-
|
|
7417
|
+
throw this.unavailableRead();
|
|
7313
7418
|
}
|
|
7314
7419
|
async listProjectIds() {
|
|
7315
|
-
|
|
7420
|
+
throw this.unavailableRead();
|
|
7316
7421
|
}
|
|
7317
7422
|
async searchLexical(_options) {
|
|
7318
|
-
|
|
7423
|
+
throw this.unavailableRead();
|
|
7319
7424
|
}
|
|
7320
7425
|
hasLexicalIndex() {
|
|
7321
7426
|
return false;
|
|
@@ -7324,25 +7429,25 @@ var init_obs_store = __esm({
|
|
|
7324
7429
|
return false;
|
|
7325
7430
|
}
|
|
7326
7431
|
async insert(_obs) {
|
|
7327
|
-
throw
|
|
7432
|
+
throw degradedWriteError("observations");
|
|
7328
7433
|
}
|
|
7329
7434
|
async update(_obs) {
|
|
7330
|
-
throw
|
|
7435
|
+
throw degradedWriteError("observations");
|
|
7331
7436
|
}
|
|
7332
7437
|
async remove(_id) {
|
|
7333
|
-
throw
|
|
7438
|
+
throw degradedWriteError("observations");
|
|
7334
7439
|
}
|
|
7335
7440
|
async bulkReplace(_obs) {
|
|
7336
|
-
throw
|
|
7441
|
+
throw degradedWriteError("observations");
|
|
7337
7442
|
}
|
|
7338
7443
|
async bulkRemoveByIds(_ids) {
|
|
7339
|
-
throw
|
|
7444
|
+
throw degradedWriteError("observations");
|
|
7340
7445
|
}
|
|
7341
7446
|
async saveIdCounter(_nextId) {
|
|
7342
|
-
throw
|
|
7447
|
+
throw degradedWriteError("observations");
|
|
7343
7448
|
}
|
|
7344
7449
|
async atomic(_fn) {
|
|
7345
|
-
throw
|
|
7450
|
+
throw degradedWriteError("observations");
|
|
7346
7451
|
}
|
|
7347
7452
|
async ensureFresh() {
|
|
7348
7453
|
return false;
|
|
@@ -7355,6 +7460,9 @@ var init_obs_store = __esm({
|
|
|
7355
7460
|
getBackendName() {
|
|
7356
7461
|
return "degraded";
|
|
7357
7462
|
}
|
|
7463
|
+
getBackendReason() {
|
|
7464
|
+
return this.reason;
|
|
7465
|
+
}
|
|
7358
7466
|
};
|
|
7359
7467
|
}
|
|
7360
7468
|
});
|
|
@@ -57009,10 +57117,10 @@ var require_retry3 = __commonJS({
|
|
|
57009
57117
|
if (!await shouldRetryFn(err)) {
|
|
57010
57118
|
return { shouldRetry: false, config: err.config };
|
|
57011
57119
|
}
|
|
57012
|
-
const
|
|
57120
|
+
const delay3 = getNextRetryDelay(config);
|
|
57013
57121
|
err.config.retryConfig.currentRetryAttempt += 1;
|
|
57014
|
-
const backoff = config.retryBackoff ? config.retryBackoff(err,
|
|
57015
|
-
setTimeout(resolve5,
|
|
57122
|
+
const backoff = config.retryBackoff ? config.retryBackoff(err, delay3) : new Promise((resolve5) => {
|
|
57123
|
+
setTimeout(resolve5, delay3);
|
|
57016
57124
|
});
|
|
57017
57125
|
if (config.onRetryAttempt) {
|
|
57018
57126
|
await config.onRetryAttempt(err);
|
|
@@ -98798,7 +98906,7 @@ async function retryBackoff(fn, strategy) {
|
|
|
98798
98906
|
retryInterval = initialInterval * Math.pow(x2, exponent) + Math.random() * 1e3;
|
|
98799
98907
|
}
|
|
98800
98908
|
const d = Math.min(retryInterval, maxInterval);
|
|
98801
|
-
await
|
|
98909
|
+
await delay2(d);
|
|
98802
98910
|
x2++;
|
|
98803
98911
|
}
|
|
98804
98912
|
}
|
|
@@ -98819,8 +98927,8 @@ function retryIntervalFromResponse(res) {
|
|
|
98819
98927
|
}
|
|
98820
98928
|
return 0;
|
|
98821
98929
|
}
|
|
98822
|
-
async function
|
|
98823
|
-
return new Promise((resolve5) => setTimeout(resolve5,
|
|
98930
|
+
async function delay2(delay3) {
|
|
98931
|
+
return new Promise((resolve5) => setTimeout(resolve5, delay3));
|
|
98824
98932
|
}
|
|
98825
98933
|
var defaultBackoff, PermanentError, TemporaryError, codeRangeRE2;
|
|
98826
98934
|
var init_retries = __esm({
|
|
@@ -145126,7 +145234,20 @@ function normalizeMiniMaxVideoRequest(input) {
|
|
|
145126
145234
|
if (ratio !== "adaptive" && ratio !== "16:9" && ratio !== "9:16" && ratio !== "1:1") {
|
|
145127
145235
|
throw new Error("MiniMax video ratio must be adaptive, 16:9, 9:16, or 1:1");
|
|
145128
145236
|
}
|
|
145129
|
-
|
|
145237
|
+
let firstFrameImageUrl;
|
|
145238
|
+
if (input.firstFrameImageUrl !== void 0) {
|
|
145239
|
+
firstFrameImageUrl = input.firstFrameImageUrl.trim();
|
|
145240
|
+
let parsed;
|
|
145241
|
+
try {
|
|
145242
|
+
parsed = new URL(firstFrameImageUrl);
|
|
145243
|
+
} catch {
|
|
145244
|
+
throw new Error("MiniMax first-frame image must be a public HTTPS URL");
|
|
145245
|
+
}
|
|
145246
|
+
if (parsed.protocol !== "https:" || parsed.username || parsed.password || sanitizeCredentials(firstFrameImageUrl) !== firstFrameImageUrl) {
|
|
145247
|
+
throw new Error("MiniMax first-frame image must be an HTTPS URL without credentials");
|
|
145248
|
+
}
|
|
145249
|
+
}
|
|
145250
|
+
return { region, model, prompt, resolution, duration, ratio, ...firstFrameImageUrl ? { firstFrameImageUrl } : {} };
|
|
145130
145251
|
}
|
|
145131
145252
|
function videoRequestConfig(input) {
|
|
145132
145253
|
const normalized = normalizeMiniMaxVideoRequest(input);
|
|
@@ -145203,7 +145324,14 @@ async function createMiniMaxVideoTask(input, dependencies = {}) {
|
|
|
145203
145324
|
headers: videoHeaders(config.apiKey),
|
|
145204
145325
|
body: JSON.stringify({
|
|
145205
145326
|
model: config.model,
|
|
145206
|
-
content: [
|
|
145327
|
+
content: [
|
|
145328
|
+
{ type: "text", text: config.prompt },
|
|
145329
|
+
...config.firstFrameImageUrl ? [{
|
|
145330
|
+
type: "image_url",
|
|
145331
|
+
image_url: { url: config.firstFrameImageUrl },
|
|
145332
|
+
role: "first_frame"
|
|
145333
|
+
}] : []
|
|
145334
|
+
],
|
|
145207
145335
|
resolution: config.resolution,
|
|
145208
145336
|
duration: config.duration,
|
|
145209
145337
|
ratio: config.ratio
|
|
@@ -145451,10 +145579,19 @@ function parseStoredRequest(value) {
|
|
|
145451
145579
|
const duration = value.duration;
|
|
145452
145580
|
const ratio = value.ratio;
|
|
145453
145581
|
const maxBytes = value.maxBytes;
|
|
145454
|
-
if (provider2 !== "minimax" && provider2 !== "minimax-cn" || region !== "global" && region !== "cn" || model !== "MiniMax-H3" || typeof prompt !== "string" || resolution !== "2K" || duration !== 5 && duration !== 10 || ratio !== "adaptive" && ratio !== "16:9" && ratio !== "9:16" && ratio !== "1:1" || typeof maxBytes !== "number" || !Number.isSafeInteger(maxBytes) || maxBytes < 1) {
|
|
145582
|
+
if (provider2 !== "minimax" && provider2 !== "minimax-cn" || region !== "global" && region !== "cn" || model !== "MiniMax-H3" || typeof prompt !== "string" || value.firstFrameImageUrl !== void 0 && typeof value.firstFrameImageUrl !== "string" || resolution !== "2K" || duration !== 5 && duration !== 10 || ratio !== "adaptive" && ratio !== "16:9" && ratio !== "9:16" && ratio !== "1:1" || typeof maxBytes !== "number" || !Number.isSafeInteger(maxBytes) || maxBytes < 1) {
|
|
145455
145583
|
throw new Error("Media video job has an invalid request payload");
|
|
145456
145584
|
}
|
|
145457
|
-
|
|
145585
|
+
const normalized = normalizeMiniMaxVideoRequest({
|
|
145586
|
+
region,
|
|
145587
|
+
model,
|
|
145588
|
+
prompt,
|
|
145589
|
+
resolution,
|
|
145590
|
+
duration,
|
|
145591
|
+
ratio,
|
|
145592
|
+
firstFrameImageUrl: value.firstFrameImageUrl
|
|
145593
|
+
});
|
|
145594
|
+
return { provider: provider2, ...normalized, maxBytes };
|
|
145458
145595
|
}
|
|
145459
145596
|
function mediaJobIdFromMaintenance(job) {
|
|
145460
145597
|
const mediaJobId = job.payload.mediaJobId;
|
|
@@ -145466,6 +145603,7 @@ function mediaJobIdFromMaintenance(job) {
|
|
|
145466
145603
|
function toVideoRequest(request) {
|
|
145467
145604
|
return {
|
|
145468
145605
|
prompt: request.prompt,
|
|
145606
|
+
firstFrameImageUrl: request.firstFrameImageUrl,
|
|
145469
145607
|
model: request.model,
|
|
145470
145608
|
region: request.region,
|
|
145471
145609
|
resolution: request.resolution,
|
|
@@ -145557,6 +145695,7 @@ function queueMiniMaxVideoGeneration(input) {
|
|
|
145557
145695
|
region: normalized.region,
|
|
145558
145696
|
model: normalized.model,
|
|
145559
145697
|
prompt: normalized.prompt,
|
|
145698
|
+
...normalized.firstFrameImageUrl ? { firstFrameImageUrl: normalized.firstFrameImageUrl } : {},
|
|
145560
145699
|
resolution: normalized.resolution,
|
|
145561
145700
|
duration: normalized.duration,
|
|
145562
145701
|
ratio: normalized.ratio,
|
|
@@ -154276,16 +154415,18 @@ async function initSessionStore(dataDir) {
|
|
|
154276
154415
|
if (_store3 && _storeDataDir3 === dataDir) return _store3;
|
|
154277
154416
|
_store3 = null;
|
|
154278
154417
|
_storeDataDir3 = null;
|
|
154418
|
+
let degradedReason = "SQLite runtime unavailable";
|
|
154279
154419
|
try {
|
|
154280
|
-
const store2 = new SessionSqliteStore();
|
|
154281
|
-
await store2.init(dataDir);
|
|
154420
|
+
const store2 = await initializeSqliteStore(() => new SessionSqliteStore(), dataDir, "Session store");
|
|
154282
154421
|
_store3 = store2;
|
|
154283
154422
|
_storeDataDir3 = dataDir;
|
|
154284
154423
|
return store2;
|
|
154285
154424
|
} catch (err) {
|
|
154286
|
-
|
|
154425
|
+
if (!isSqliteUnavailableError(err)) throw err;
|
|
154426
|
+
degradedReason = formatSqliteFailure(err);
|
|
154427
|
+
console.error(`[memorix] SessionSqliteStore unavailable, running in degraded read-only mode: ${degradedReason}`);
|
|
154287
154428
|
}
|
|
154288
|
-
const store = new SessionGracefulDegrade();
|
|
154429
|
+
const store = new SessionGracefulDegrade(degradedReason);
|
|
154289
154430
|
await store.init(dataDir);
|
|
154290
154431
|
_store3 = store;
|
|
154291
154432
|
_storeDataDir3 = dataDir;
|
|
@@ -154297,6 +154438,7 @@ var init_session_store = __esm({
|
|
|
154297
154438
|
"use strict";
|
|
154298
154439
|
init_esm_shims();
|
|
154299
154440
|
init_sqlite_db();
|
|
154441
|
+
init_sqlite_reliability();
|
|
154300
154442
|
SessionSqliteStore = class {
|
|
154301
154443
|
db = null;
|
|
154302
154444
|
dataDir = "";
|
|
@@ -154385,7 +154527,7 @@ var init_session_store = __esm({
|
|
|
154385
154527
|
}
|
|
154386
154528
|
const stmtComplete = this._stmtCompleteActive;
|
|
154387
154529
|
const stmtIns = this.stmtInsert;
|
|
154388
|
-
|
|
154530
|
+
return retrySqliteBusy(async () => this.db.transaction(() => {
|
|
154389
154531
|
let completedCount = 0;
|
|
154390
154532
|
for (const pid of projectIds) {
|
|
154391
154533
|
const info = stmtComplete.run({ pid, now: now3 });
|
|
@@ -154393,18 +154535,24 @@ var init_session_store = __esm({
|
|
|
154393
154535
|
}
|
|
154394
154536
|
stmtIns.run(sessionToRow(newSession));
|
|
154395
154537
|
return completedCount;
|
|
154396
|
-
})();
|
|
154397
|
-
return result;
|
|
154538
|
+
})(), "Session rollover");
|
|
154398
154539
|
}
|
|
154399
154540
|
getBackendName() {
|
|
154400
154541
|
return "sqlite";
|
|
154401
154542
|
}
|
|
154402
154543
|
};
|
|
154403
154544
|
SessionGracefulDegrade = class {
|
|
154545
|
+
constructor(reason = "SQLite runtime unavailable") {
|
|
154546
|
+
this.reason = reason;
|
|
154547
|
+
}
|
|
154548
|
+
reason;
|
|
154404
154549
|
warned = false;
|
|
154550
|
+
unavailableRead() {
|
|
154551
|
+
return degradedReadError("sessions");
|
|
154552
|
+
}
|
|
154405
154553
|
warn() {
|
|
154406
154554
|
if (!this.warned) {
|
|
154407
|
-
console.error("[memorix] SessionStore: SQLite unavailable \u2014 sessions
|
|
154555
|
+
console.error("[memorix] SessionStore: SQLite unavailable \u2014 sessions cannot be read or written. Install a supported SQLite runtime.");
|
|
154408
154556
|
this.warned = true;
|
|
154409
154557
|
}
|
|
154410
154558
|
}
|
|
@@ -154412,33 +154560,39 @@ var init_session_store = __esm({
|
|
|
154412
154560
|
this.warn();
|
|
154413
154561
|
}
|
|
154414
154562
|
async loadAll() {
|
|
154415
|
-
|
|
154563
|
+
throw this.unavailableRead();
|
|
154416
154564
|
}
|
|
154417
154565
|
async getById(_id) {
|
|
154418
|
-
|
|
154566
|
+
throw this.unavailableRead();
|
|
154419
154567
|
}
|
|
154420
154568
|
async loadByProject(_projectId) {
|
|
154421
|
-
|
|
154569
|
+
throw this.unavailableRead();
|
|
154422
154570
|
}
|
|
154423
154571
|
async loadActive(_projectId) {
|
|
154424
|
-
|
|
154572
|
+
throw this.unavailableRead();
|
|
154425
154573
|
}
|
|
154426
154574
|
async insert(_session) {
|
|
154427
154575
|
this.warn();
|
|
154576
|
+
throw degradedWriteError("sessions");
|
|
154428
154577
|
}
|
|
154429
154578
|
async update(_session) {
|
|
154430
154579
|
this.warn();
|
|
154580
|
+
throw degradedWriteError("sessions");
|
|
154431
154581
|
}
|
|
154432
154582
|
async bulkUpdate(_sessions) {
|
|
154433
154583
|
this.warn();
|
|
154584
|
+
throw degradedWriteError("sessions");
|
|
154434
154585
|
}
|
|
154435
154586
|
async atomicRolloverInsert(_newSession, _projectIds, _now) {
|
|
154436
154587
|
this.warn();
|
|
154437
|
-
|
|
154588
|
+
throw degradedWriteError("sessions");
|
|
154438
154589
|
}
|
|
154439
154590
|
getBackendName() {
|
|
154440
154591
|
return "degraded";
|
|
154441
154592
|
}
|
|
154593
|
+
getBackendReason() {
|
|
154594
|
+
return this.reason;
|
|
154595
|
+
}
|
|
154442
154596
|
};
|
|
154443
154597
|
_store3 = null;
|
|
154444
154598
|
_storeDataDir3 = null;
|
|
@@ -169896,7 +170050,7 @@ var MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
|
|
|
169896
170050
|
function getMcpServerInfo() {
|
|
169897
170051
|
return {
|
|
169898
170052
|
name: "memorix",
|
|
169899
|
-
version: true ? "1.9.
|
|
170053
|
+
version: true ? "1.9.4" : "1.0.1"
|
|
169900
170054
|
};
|
|
169901
170055
|
}
|
|
169902
170056
|
function createMcpDiscoverResult(capabilities, serverInfo) {
|
|
@@ -174202,6 +174356,7 @@ ${lines.join("\n")}` }] };
|
|
|
174202
174356
|
} : {},
|
|
174203
174357
|
...mediaGenerationEnabled ? {
|
|
174204
174358
|
image: z627.string().optional().describe("Base64-encoded reference image for image-to-image generation."),
|
|
174359
|
+
firstFrameImageUrl: z627.string().optional().describe("Public HTTPS first-frame image URL for MiniMax video generation; stored with the queued job."),
|
|
174205
174360
|
region: z627.enum(["global", "cn"]).optional().describe("MiniMax deployment region."),
|
|
174206
174361
|
n: z627.number().int().min(1).max(4).optional().describe("Image output count."),
|
|
174207
174362
|
ratio: z627.enum(["adaptive", "1:1", "16:9", "4:3", "3:2", "2:3", "3:4", "9:16", "21:9"]).optional().describe("Image or video aspect ratio."),
|
|
@@ -174211,7 +174366,7 @@ ${lines.join("\n")}` }] };
|
|
|
174211
174366
|
} : {}
|
|
174212
174367
|
}
|
|
174213
174368
|
},
|
|
174214
|
-
async ({ action, path: assetPath, assetId, jobId, kind, limit: limit2, title, narrative, prompt, image, model, provider: provider2, language, region, n, ratio, width, height, duration, maxPages, maxChars, attach }) => {
|
|
174369
|
+
async ({ action, path: assetPath, assetId, jobId, kind, limit: limit2, title, narrative, prompt, image, firstFrameImageUrl, model, provider: provider2, language, region, n, ratio, width, height, duration, maxPages, maxChars, attach }) => {
|
|
174215
174370
|
const unresolved = requireResolvedProject("manage controlled media");
|
|
174216
174371
|
if (unresolved) return unresolved;
|
|
174217
174372
|
const safeError4 = (error) => sanitizeCredentials(
|
|
@@ -174381,6 +174536,7 @@ ${lines.join("\n")}` }] };
|
|
|
174381
174536
|
dataDir: projectDir2,
|
|
174382
174537
|
projectId: project.id,
|
|
174383
174538
|
prompt,
|
|
174539
|
+
firstFrameImageUrl,
|
|
174384
174540
|
...model === "MiniMax-H3" ? { model } : {},
|
|
174385
174541
|
...region ? { region } : {},
|
|
174386
174542
|
...videoRatio ? { ratio: videoRatio } : {},
|