mixdog 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -434
- package/package.json +18 -17
- package/scripts/gate-local.mjs +93 -0
- package/scripts/lib/gate-scheduler.mjs +24 -0
- package/scripts/lib/run-node-tests.mjs +5 -1
- package/scripts/release-paths.mjs +22 -1
- package/scripts/test-direct.mjs +2 -1
- package/scripts/test.mjs +3 -1
- package/src/defaults/agents.json +0 -12
- package/src/defaults/mixdog-config.template.json +1 -2
- package/src/defaults/skills/docx/SKILL.md +7 -4
- package/src/defaults/skills/docx/references/html.md +46 -0
- package/src/defaults/skills/docx/references/native-authoring.md +18 -4
- package/src/defaults/skills/pdf/SKILL.md +10 -2
- package/src/defaults/skills/pdf/references/html.md +64 -0
- package/src/defaults/skills/pptx/references/html.md +1 -1
- package/src/defaults/skills/xlsx/SKILL.md +7 -3
- package/src/defaults/skills/xlsx/references/html.md +40 -0
- package/src/defaults/skills/xlsx/references/report-design.md +21 -4
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
- package/src/runtime/agent/orchestrator/internal-agents.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +6 -5
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +50 -9
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +28 -1
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +34 -8
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/transcript-restore/agent-envelope.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +1 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +3 -1
- package/src/runtime/attachments/pdf-extract.mjs +7 -3
- package/src/runtime/computer-bridge/client.mjs +1 -1
- package/src/runtime/memory/index.mjs +4 -15
- package/src/runtime/memory/lib/core-memory-store.mjs +1 -1
- package/src/runtime/memory/lib/cycle-llm-adapters.mjs +0 -2
- package/src/runtime/memory/lib/cycle-scheduler/backlog-probe.mjs +3 -11
- package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +1 -3
- package/src/runtime/memory/lib/cycle-scheduler/scheduled-enqueue.mjs +1 -11
- package/src/runtime/memory/lib/cycle-scheduler/tick-loop.mjs +0 -2
- package/src/runtime/memory/lib/cycle-scheduler.mjs +4 -13
- package/src/runtime/memory/lib/cycle-signatures.mjs +0 -6
- package/src/runtime/memory/lib/cycle1/cycle1-rows.mjs +1 -1
- package/src/runtime/memory/lib/cycle1/cycle1-window.mjs +2 -2
- package/src/runtime/memory/lib/embedding-reindex.mjs +1 -1
- package/src/runtime/memory/lib/http-router/lifecycle-routes.mjs +0 -1
- package/src/runtime/memory/lib/memory-action-handlers/cycle-actions.mjs +7 -52
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +6 -22
- package/src/runtime/memory/lib/memory-action-handlers/cycle-rebuild-action.mjs +10 -17
- package/src/runtime/memory/lib/memory-action-handlers/maintenance-actions.mjs +1 -3
- package/src/runtime/memory/lib/memory-action-handlers/manage-actions.mjs +2 -4
- package/src/runtime/memory/lib/memory-action-handlers.mjs +2 -4
- package/src/runtime/memory/lib/memory-cycle-requests.mjs +1 -1
- package/src/runtime/memory/lib/{memory-cycle2-shared.mjs → memory-cycle-shared.mjs} +14 -16
- package/src/runtime/memory/lib/memory-cycle.mjs +3 -2
- package/src/runtime/memory/lib/memory-cycle1.mjs +1 -1
- package/src/runtime/memory/lib/memory-embed.mjs +14 -1
- package/src/runtime/memory/lib/memory-ops-policy.mjs +8 -11
- package/src/runtime/memory/lib/memory-schema/entries.mjs +0 -1
- package/src/runtime/memory/lib/memory.mjs +2 -6
- package/src/runtime/memory/lib/pg/adapter.mjs +1 -1
- package/src/runtime/memory/lib/query-handlers.mjs +1 -1
- package/src/runtime/memory/lib/query-hybrid-search.mjs +1 -1
- package/src/runtime/memory/lib/query-maintenance-handlers.mjs +0 -6
- package/src/runtime/memory/lib/recall-format.mjs +1 -1
- package/src/runtime/office/authoring/docx-html-build.mjs +375 -0
- package/src/runtime/office/authoring/docx-html-measure.mjs +561 -0
- package/src/runtime/office/authoring/docx-html-runner.mjs +102 -0
- package/src/runtime/office/authoring/html-browser.mjs +61 -0
- package/src/runtime/office/authoring/html-document-author.mjs +181 -0
- package/src/runtime/office/authoring/html-source-drift.mjs +36 -0
- package/src/runtime/office/authoring/pdf-author-action.mjs +266 -0
- package/src/runtime/office/authoring/pdf-html-charts.mjs +379 -0
- package/src/runtime/office/authoring/pdf-html-runner.mjs +317 -0
- package/src/runtime/office/authoring/pptx-author-action.mjs +44 -22
- package/src/runtime/office/authoring/pptx-author-session.mjs +12 -6
- package/src/runtime/office/authoring/pptx-html-build.mjs +23 -4
- package/src/runtime/office/authoring/pptx-html-measure.mjs +38 -44
- package/src/runtime/office/authoring/pptx-html-runner.mjs +18 -3
- package/src/runtime/office/authoring/pptx-receipt.mjs +39 -31
- package/src/runtime/office/authoring/pptx-review-artifacts.mjs +9 -1
- package/src/runtime/office/authoring/pptx-script-runner.mjs +6 -2
- package/src/runtime/office/authoring/xlsx-html-build.mjs +365 -0
- package/src/runtime/office/authoring/xlsx-html-measure.mjs +257 -0
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +139 -0
- package/src/runtime/office/capabilities-catalog.mjs +8 -0
- package/src/runtime/office/capabilities-signatures.mjs +18 -6
- package/src/runtime/office/capabilities.mjs +26 -1
- package/src/runtime/office/com/office-com-host.ps1 +133 -17
- package/src/runtime/office/core/office-actions-batch.mjs +16 -1
- package/src/runtime/office/core/office-actions-inspect.mjs +3 -2
- package/src/runtime/office/core/office-actions-lifecycle.mjs +6 -2
- package/src/runtime/office/core/office-actions-render.mjs +4 -1
- package/src/runtime/office/core/office-finalize/review-stage.mjs +15 -2
- package/src/runtime/office/core/office-qa/design-review-stage.mjs +9 -0
- package/src/runtime/office/core/office-session-dispatch.mjs +3 -0
- package/src/runtime/office/core/office-sessionless-actions.mjs +7 -2
- package/src/runtime/office/core/office-sessions.mjs +19 -2
- package/src/runtime/office/pdf/pdf-writer.mjs +1 -1
- package/src/runtime/office/portable/docx-formatting.mjs +21 -0
- package/src/runtime/office/portable/ooxml-validator.mjs +22 -1
- package/src/runtime/office/portable/portable-chart.mjs +10 -2
- package/src/runtime/office/portable/portable-docx-edits.mjs +12 -6
- package/src/runtime/office/portable/portable-docx-operations.mjs +75 -1
- package/src/runtime/office/portable/portable-docx-xml.mjs +49 -6
- package/src/runtime/office/portable/portable-docx.mjs +2 -0
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +2 -0
- package/src/runtime/office/portable/portable-validation.mjs +6 -3
- package/src/runtime/office/portable/portable-xlsx-cell-values.mjs +87 -0
- package/src/runtime/office/portable/portable-xlsx-charts.mjs +55 -13
- package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +1 -1
- package/src/runtime/office/portable/xlsx-contract.mjs +82 -3
- package/src/runtime/office/quality/assurance-checklist.mjs +2 -2
- package/src/runtime/office/quality/assurance-rendered.mjs +27 -1
- package/src/runtime/office/quality/assurance-structure-docx.mjs +44 -0
- package/src/runtime/office/quality/assurance-structure-pptx.mjs +24 -6
- package/src/runtime/office/quality/assurance-structure-xlsx.mjs +50 -1
- package/src/runtime/office/quality/design-review-critique.mjs +3 -2
- package/src/runtime/office/quality/document-brief.mjs +44 -0
- package/src/runtime/office/quality/inline-audit.mjs +7 -2
- package/src/runtime/office/quality/quality-pipeline.mjs +9 -1
- package/src/runtime/office/tool-defs.mjs +2 -2
- package/src/runtime/shared/llm/quota-value-estimate.mjs +317 -0
- package/src/runtime/shared/llm/usage-ledger-quota.mjs +266 -63
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +35 -0
- package/src/runtime/shared/llm/usage-ledger-worker.mjs +2 -1
- package/src/runtime/shared/llm/usage-ledger.mjs +10 -1
- package/src/runtime/shared/provider-accounts.mjs +11 -1
- package/src/runtime/shared/statusline/statusline-segments.mjs +4 -4
- package/src/runtime/shared/tool-execution-contract.mjs +1 -1
- package/src/runtime/shared/wait-until.test-support.mjs +33 -0
- package/src/session-runtime/boot/apis.mjs +1 -1
- package/src/session-runtime/services/channel-admin.mjs +4 -3
- package/src/session-runtime/services/usage-stats-model.mjs +22 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +6 -1
- package/src/session-runtime/turn/session-ops.mjs +15 -9
- package/src/session-runtime/usage-stats-api.mjs +34 -2
- package/src/standalone/agent-dispatch-broker.mjs +1 -1
- package/src/standalone/local-session-runtime.mjs +488 -0
- package/src/standalone/session-protocol.mjs +1 -0
- package/src/standalone/session-runtime-inline-host.mjs +1 -1
- package/src/tui/hooks/useSession.mjs +1 -1
- package/src/tui/session/session-api/commands.mjs +1 -1
- package/src/tui/session/session-api/integrations.mjs +3 -0
- package/src/tui/session/session-flow/auto-clear.mjs +6 -7
- package/src/tui/session/tool-card-results.mjs +1 -1
- package/src/tui/session/turn.mjs +5 -0
- package/src/tui/session-local.mjs +3 -488
- package/src/tui/session.mjs +1 -1
- package/src/ui/statusline-agents.mjs +0 -1
- package/src/rules/agent/41-cycle2-agent.md +0 -24
- package/src/runtime/memory/lib/cycle-scheduler/cycle2-runs.mjs +0 -120
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +0 -110
- package/src/runtime/memory/lib/memory-cycle2-quarantine.mjs +0 -99
- package/src/runtime/memory/lib/memory-cycle2-review.mjs +0 -240
- package/src/runtime/memory/lib/memory-cycle2.mjs +0 -191
|
@@ -48,13 +48,17 @@ function pageBodyText(content) {
|
|
|
48
48
|
if (typeof item?.str !== 'string') continue;
|
|
49
49
|
if (item.str) {
|
|
50
50
|
const placement = runPlacement(item);
|
|
51
|
+
// A run on another baseline is another line even when the writer marked no line end (a browser's
|
|
52
|
+
// print does not): "784" over its label read as "784office". A baseline shift under half the
|
|
53
|
+
// smaller run's size (a superscript, a mixed-size run) stays on the line.
|
|
54
|
+
const shift = placement && cursor ? Math.abs(placement.line - cursor.line) : 0;
|
|
55
|
+
const newLine = shift > Math.min(placement?.size || 0, cursor?.size || 0) * 0.5;
|
|
56
|
+
if (newLine && body && !body.endsWith('\n')) body += '\n';
|
|
51
57
|
// A writer splits one word into several runs for kerning, and a
|
|
52
58
|
// Korean line into a run per token; joining those with a space
|
|
53
59
|
// invents "2026 년". Only a gap the page itself leaves is a space.
|
|
54
60
|
const separated =
|
|
55
|
-
placement && cursor && placement.
|
|
56
|
-
? placement.start - cursor.end > cursor.size * 0.22
|
|
57
|
-
: !placement || !cursor;
|
|
61
|
+
placement && cursor && !newLine ? placement.start - cursor.end > cursor.size * 0.22 : !placement || !cursor;
|
|
58
62
|
const glued = !body || body.endsWith('\n') || body.endsWith(' ') || item.str.startsWith(' ') || !separated;
|
|
59
63
|
body += (glued ? '' : ' ') + item.str;
|
|
60
64
|
cursor = placement;
|
|
@@ -411,7 +411,7 @@ function computerToolResult(value, args) {
|
|
|
411
411
|
}
|
|
412
412
|
return {
|
|
413
413
|
content,
|
|
414
|
-
...(canonicalComputerResultIsError(text, args) ? { isError: true } : {}),
|
|
414
|
+
...(value.isError === true || canonicalComputerResultIsError(text, args) ? { isError: true } : {}),
|
|
415
415
|
};
|
|
416
416
|
}
|
|
417
417
|
|
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
shutdownEmbeddingProvider,
|
|
52
52
|
warmupEmbeddingProvider,
|
|
53
53
|
} from './lib/embedding-provider.mjs';
|
|
54
|
-
import { runCycle1,
|
|
54
|
+
import { runCycle1, parseInterval, flushEmbeddingDirty, flushRawEmbeddings } from './lib/memory-cycle.mjs';
|
|
55
55
|
import { callAgentDispatch } from './lib/agent-ipc.mjs';
|
|
56
56
|
import {
|
|
57
57
|
cancelCoalescedCycleRetries,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
import { writeJsonAtomicSync } from '../shared/atomic-file.mjs';
|
|
74
74
|
import { safeIpcSend } from '../shared/safe-ipc-send.mjs';
|
|
75
75
|
import { resolvePluginData, mixdogHome } from '../shared/plugin-paths.mjs';
|
|
76
|
-
import { scheduledCycle1Signature
|
|
76
|
+
import { scheduledCycle1Signature } from './lib/cycle-signatures.mjs';
|
|
77
77
|
import { createTranscriptIngest } from './lib/transcript-ingest.mjs';
|
|
78
78
|
import { createCycleLlmAdapters } from './lib/cycle-llm-adapters.mjs';
|
|
79
79
|
import { createCycleScheduler } from './lib/cycle-scheduler.mjs';
|
|
@@ -333,20 +333,15 @@ async function getCycleLastRun() {
|
|
|
333
333
|
const obj = JSON.parse(raw);
|
|
334
334
|
return {
|
|
335
335
|
cycle1: Number(obj.cycle1) || 0,
|
|
336
|
-
cycle2: Number(obj.cycle2) || 0,
|
|
337
336
|
// Heartbeat (every attempt, success or skip) is tracked separately from
|
|
338
337
|
// the success timestamps above so a long string of failed/skipped runs
|
|
339
338
|
// cannot disguise itself as a healthy keeper.
|
|
340
339
|
cycle1_heartbeat: Number(obj.cycle1_heartbeat) || 0,
|
|
341
|
-
// Last cycle2 failure message; cleared to '' on success.
|
|
342
|
-
cycle2_last_error: typeof obj.cycle2_last_error === 'string' ? obj.cycle2_last_error : '',
|
|
343
340
|
};
|
|
344
341
|
} catch {
|
|
345
342
|
return {
|
|
346
343
|
cycle1: 0,
|
|
347
|
-
cycle2: 0,
|
|
348
344
|
cycle1_heartbeat: 0,
|
|
349
|
-
cycle2_last_error: '',
|
|
350
345
|
};
|
|
351
346
|
}
|
|
352
347
|
}
|
|
@@ -373,7 +368,7 @@ async function refreshCoreMemorySnapshot(reason = 'mutation') {
|
|
|
373
368
|
const CYCLE_STATE_FILE = path.join(DATA_DIR, 'memory-cycle-state.json');
|
|
374
369
|
|
|
375
370
|
const _cycleLlmAdapters = createCycleLlmAdapters({ callAgentDispatch });
|
|
376
|
-
const { getCycle1CallLlm
|
|
371
|
+
const { getCycle1CallLlm } = _cycleLlmAdapters;
|
|
377
372
|
|
|
378
373
|
const _cycleScheduler = createCycleScheduler({
|
|
379
374
|
getDb: () => db,
|
|
@@ -388,9 +383,7 @@ const _cycleScheduler = createCycleScheduler({
|
|
|
388
383
|
readMainConfig,
|
|
389
384
|
memoryCyclesEnabled,
|
|
390
385
|
getCycle1CallLlm,
|
|
391
|
-
getCycle2CallLlm,
|
|
392
386
|
runCycle1,
|
|
393
|
-
runCycle2,
|
|
394
387
|
parseInterval,
|
|
395
388
|
flushRawEmbeddings,
|
|
396
389
|
claimAndMarkScheduledCycle,
|
|
@@ -398,13 +391,11 @@ const _cycleScheduler = createCycleScheduler({
|
|
|
398
391
|
scheduleCoalescedCycleRetry,
|
|
399
392
|
cancelCoalescedCycleRetries,
|
|
400
393
|
scheduledCycle1Signature,
|
|
401
|
-
scheduledCycle2Signature,
|
|
402
394
|
cycleStateFile: CYCLE_STATE_FILE,
|
|
403
395
|
});
|
|
404
|
-
// Cycle1 run primitives
|
|
396
|
+
// Cycle1 run primitives used by MCP action handlers below.
|
|
405
397
|
const _startCycle1Run = _cycleScheduler.startCycle1Run;
|
|
406
398
|
const _awaitCycle1Run = _cycleScheduler.awaitCycle1Run;
|
|
407
|
-
const _finalizeCycle2Run = _cycleScheduler.finalizeCycle2Run;
|
|
408
399
|
|
|
409
400
|
// Transcript watcher lifecycle stays in the facade (owns _transcriptIngest);
|
|
410
401
|
// the cycle tick loop start/stop is delegated to the scheduler.
|
|
@@ -509,10 +500,8 @@ const _actionHandlers = createMemoryActionHandlers({
|
|
|
509
500
|
dumpSessionRootChunks,
|
|
510
501
|
awaitCycle1Run: _awaitCycle1Run,
|
|
511
502
|
startCycle1Run: _startCycle1Run,
|
|
512
|
-
finalizeCycle2Run: _finalizeCycle2Run,
|
|
513
503
|
refreshCoreMemoryFile: refreshCoreMemorySnapshot,
|
|
514
504
|
getSchedulerCycle1InFlight: () => _cycleScheduler.getCycle1InFlight(),
|
|
515
|
-
getCycle2CallLlm,
|
|
516
505
|
ingestTranscriptFile,
|
|
517
506
|
cwdFromTranscriptPath,
|
|
518
507
|
});
|
|
@@ -9,7 +9,7 @@ import { getDatabase, embeddingToSql } from './memory.mjs';
|
|
|
9
9
|
import { VALID_CATEGORY } from './memory-categories.mjs';
|
|
10
10
|
import { cachedEmbedTextBatch } from './memory-embed.mjs';
|
|
11
11
|
import { checkedConnect } from './pg/adapter.mjs';
|
|
12
|
-
import { throwIfAborted } from './memory-
|
|
12
|
+
import { throwIfAborted } from './memory-cycle-shared.mjs';
|
|
13
13
|
import { findCoreKeyRows } from './core-memory-uniqueness.mjs';
|
|
14
14
|
|
|
15
15
|
const CORE_ELEMENT_DERIVE_LENGTH = 40;
|
|
@@ -30,9 +30,7 @@ export function createCycleLlmAdapters({ callAgentDispatch }) {
|
|
|
30
30
|
// unhandled rejection that killed the memory runtime. Keep the factory
|
|
31
31
|
// contract: each getter returns the (memoized) adapter function.
|
|
32
32
|
const cycle1 = buildAdapter('cycle1-agent');
|
|
33
|
-
const cycle2 = buildAdapter('cycle2-agent');
|
|
34
33
|
return {
|
|
35
34
|
getCycle1CallLlm: () => cycle1,
|
|
36
|
-
getCycle2CallLlm: () => cycle2,
|
|
37
35
|
};
|
|
38
36
|
}
|
|
@@ -6,13 +6,6 @@ async function countRows(db, sql, params) {
|
|
|
6
6
|
return Number((await db.query(sql, params)).rows[0]?.c ?? 0);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export function countPendingCycle2Roots(db) {
|
|
10
|
-
return countRows(
|
|
11
|
-
db,
|
|
12
|
-
`SELECT COUNT(*) c FROM entries WHERE is_root = 1 AND cycle2_reviewed_at IS NULL AND duplicate_of IS NULL`
|
|
13
|
-
);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
9
|
// Per-tick backlog counts for the state file / statusline, the backlog
|
|
17
10
|
// warning, and the opportunistic raw-embedding flush while rows are unchunked.
|
|
18
11
|
export function createBacklogProbe({ getDb, ledger, log, flushRawEmbeddings }) {
|
|
@@ -46,10 +39,9 @@ export function createBacklogProbe({ getDb, ledger, log, flushRawEmbeddings }) {
|
|
|
46
39
|
AND (reviewed_at IS NULL OR reviewed_at < $1)`,
|
|
47
40
|
[now - CYCLE1_OMITTED_COOLDOWN_MS]
|
|
48
41
|
);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
ledger.warn(`backlog unchunked=${unchunked} eligible=${unchunkedEligible} cycle2_pending=${cycle2Pending}`);
|
|
42
|
+
ledger.setBacklog({ unchunked, unchunked_eligible: unchunkedEligible, at: now });
|
|
43
|
+
if (unchunked > BACKLOG_WARN_PENDING) {
|
|
44
|
+
ledger.warn(`backlog unchunked=${unchunked} eligible=${unchunkedEligible}`);
|
|
53
45
|
}
|
|
54
46
|
if (unchunked > 0) flushRawEmbeddingsOnce(db);
|
|
55
47
|
} catch {
|
|
@@ -9,10 +9,9 @@ const BACKLOG_WARN_FAILURES = 5;
|
|
|
9
9
|
export function createCycleHealthLedger({ cycleStateFile, log }) {
|
|
10
10
|
const health = {
|
|
11
11
|
cycle1: { last_success_at: 0, last_error_at: 0, last_error: null, consecutive_failures: 0 },
|
|
12
|
-
cycle2: { last_success_at: 0, last_error_at: 0, last_error: null, consecutive_failures: 0 },
|
|
13
12
|
};
|
|
14
13
|
let running = null; // { cycle, started_at, pid }
|
|
15
|
-
let backlog = { unchunked: 0,
|
|
14
|
+
let backlog = { unchunked: 0, at: 0 };
|
|
16
15
|
let lastWarnAt = 0;
|
|
17
16
|
|
|
18
17
|
function write() {
|
|
@@ -74,7 +73,6 @@ export function createCycleHealthLedger({ cycleStateFile, log }) {
|
|
|
74
73
|
// state file reports 0 until the next run.
|
|
75
74
|
function hydrateSuccess(last) {
|
|
76
75
|
if (last?.cycle1 > 0 && !health.cycle1.last_success_at) health.cycle1.last_success_at = last.cycle1;
|
|
77
|
-
if (last?.cycle2 > 0 && !health.cycle2.last_success_at) health.cycle2.last_success_at = last.cycle2;
|
|
78
76
|
write();
|
|
79
77
|
}
|
|
80
78
|
|
|
@@ -5,9 +5,7 @@ export function createScheduledEnqueue({
|
|
|
5
5
|
getConfig,
|
|
6
6
|
claimAndMarkScheduledCycle,
|
|
7
7
|
scheduledCycle1Signature,
|
|
8
|
-
scheduledCycle2Signature,
|
|
9
8
|
scheduleScheduledCycle1,
|
|
10
|
-
scheduleScheduledCycle2,
|
|
11
9
|
}) {
|
|
12
10
|
function periodicCycle1Config() {
|
|
13
11
|
return {
|
|
@@ -38,13 +36,5 @@ export function createScheduledEnqueue({
|
|
|
38
36
|
}
|
|
39
37
|
}
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
const config = getConfig()?.cycle2 || {};
|
|
43
|
-
const signature = scheduledCycle2Signature(config);
|
|
44
|
-
if (await claimScheduledSlot('cycle2', intervalMs, signature, config)) {
|
|
45
|
-
scheduleScheduledCycle2(config, signature);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return { periodicCycle1Config, enqueueScheduledCycle1, enqueueScheduledCycle2 };
|
|
39
|
+
return { periodicCycle1Config, enqueueScheduledCycle1 };
|
|
50
40
|
}
|
|
@@ -30,12 +30,10 @@ export function createCycleTickLoop({
|
|
|
30
30
|
setConfig(mainConfig);
|
|
31
31
|
const cyclesOn = memoryCyclesEnabled();
|
|
32
32
|
const cycle1Ms = parseInterval(mainConfig?.cycle1?.interval || '10m');
|
|
33
|
-
const cycle2Ms = parseInterval(mainConfig?.cycle2?.interval || '1h');
|
|
34
33
|
const now = Date.now();
|
|
35
34
|
const last = await getCycleLastRun();
|
|
36
35
|
if (cyclesOn) {
|
|
37
36
|
if (periodicCycleDue(last.cycle1, startedAt, cycle1Ms, now)) await enqueue.enqueueScheduledCycle1(cycle1Ms);
|
|
38
|
-
if (periodicCycleDue(last.cycle2, startedAt, cycle2Ms, now)) await enqueue.enqueueScheduledCycle2(cycle2Ms);
|
|
39
37
|
}
|
|
40
38
|
await probeBacklog(now);
|
|
41
39
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Owns the mutually-referential cycle machinery: the cycle-health ledger and
|
|
4
4
|
// run-state file, the cycle1 outer coalesce layer, the scheduled enqueue /
|
|
5
|
-
// retry paths for cycle1
|
|
5
|
+
// retry paths for cycle1, checkCycles(), and the self-rescheduling tick
|
|
6
6
|
// loop. The phases live under cycle-scheduler/. index.mjs keeps lifecycle
|
|
7
7
|
// ownership by injecting live getters (getDb/getConfig/setConfig) plus the
|
|
8
8
|
// cycle runners and LLM adapters.
|
|
@@ -15,15 +15,14 @@
|
|
|
15
15
|
// log -> __mixdogMemoryLog
|
|
16
16
|
// getCycleLastRun / setCycleLastRun -> meta-backed cycle timestamps
|
|
17
17
|
// readMainConfig / memoryCyclesEnabled -> config-flag helpers
|
|
18
|
-
//
|
|
19
|
-
// runCycle1 /
|
|
18
|
+
// getCycle1CallLlm -> in-process LLM adapter
|
|
19
|
+
// runCycle1 / parseInterval / flushRawEmbeddings
|
|
20
20
|
// claimAndMarkScheduledCycle / resolveCoalesceMaxRetries /
|
|
21
21
|
// scheduleCoalescedCycleRetry -> coalesced queue primitives
|
|
22
|
-
//
|
|
22
|
+
// scheduledCycle1Signature -> queue signature
|
|
23
23
|
// cycleStateFile -> path to memory-cycle-state.json
|
|
24
24
|
import { createCycleHealthLedger } from './cycle-scheduler/health-ledger.mjs';
|
|
25
25
|
import { createCycle1Runs } from './cycle-scheduler/cycle1-runs.mjs';
|
|
26
|
-
import { createCycle2Runs } from './cycle-scheduler/cycle2-runs.mjs';
|
|
27
26
|
import { createScheduledEnqueue } from './cycle-scheduler/scheduled-enqueue.mjs';
|
|
28
27
|
import { createBacklogProbe } from './cycle-scheduler/backlog-probe.mjs';
|
|
29
28
|
import { createCycleTickLoop } from './cycle-scheduler/tick-loop.mjs';
|
|
@@ -42,9 +41,7 @@ export function createCycleScheduler(deps) {
|
|
|
42
41
|
readMainConfig,
|
|
43
42
|
memoryCyclesEnabled,
|
|
44
43
|
getCycle1CallLlm,
|
|
45
|
-
getCycle2CallLlm,
|
|
46
44
|
runCycle1,
|
|
47
|
-
runCycle2,
|
|
48
45
|
parseInterval,
|
|
49
46
|
flushRawEmbeddings,
|
|
50
47
|
claimAndMarkScheduledCycle,
|
|
@@ -52,7 +49,6 @@ export function createCycleScheduler(deps) {
|
|
|
52
49
|
scheduleCoalescedCycleRetry,
|
|
53
50
|
cancelCoalescedCycleRetries,
|
|
54
51
|
scheduledCycle1Signature,
|
|
55
|
-
scheduledCycle2Signature,
|
|
56
52
|
cycleStateFile,
|
|
57
53
|
} = deps;
|
|
58
54
|
|
|
@@ -68,15 +64,12 @@ export function createCycleScheduler(deps) {
|
|
|
68
64
|
setCycleLastRun,
|
|
69
65
|
...queue,
|
|
70
66
|
});
|
|
71
|
-
const cycle2 = createCycle2Runs({ ledger, getDb, log, getCycle2CallLlm, runCycle2, setCycleLastRun, ...queue });
|
|
72
67
|
const enqueue = createScheduledEnqueue({
|
|
73
68
|
getDb,
|
|
74
69
|
getConfig,
|
|
75
70
|
claimAndMarkScheduledCycle,
|
|
76
71
|
scheduledCycle1Signature,
|
|
77
|
-
scheduledCycle2Signature,
|
|
78
72
|
scheduleScheduledCycle1: cycle1.scheduleScheduledCycle1,
|
|
79
|
-
scheduleScheduledCycle2: cycle2.scheduleScheduledCycle2,
|
|
80
73
|
});
|
|
81
74
|
const backlog = createBacklogProbe({ getDb, ledger, log, flushRawEmbeddings });
|
|
82
75
|
const tick = createCycleTickLoop({
|
|
@@ -97,7 +90,6 @@ export function createCycleScheduler(deps) {
|
|
|
97
90
|
// running state.
|
|
98
91
|
function resetInFlight() {
|
|
99
92
|
cycle1.reset();
|
|
100
|
-
cycle2.reset();
|
|
101
93
|
backlog.reset();
|
|
102
94
|
tick.reset();
|
|
103
95
|
ledger.resetRunning();
|
|
@@ -113,7 +105,6 @@ export function createCycleScheduler(deps) {
|
|
|
113
105
|
// run primitives used by MCP action handlers
|
|
114
106
|
startCycle1Run: cycle1.startCycle1Run,
|
|
115
107
|
awaitCycle1Run: cycle1.awaitCycle1Run,
|
|
116
|
-
finalizeCycle2Run: cycle2.finalizeCycle2Run,
|
|
117
108
|
periodicCycle1Config: enqueue.periodicCycle1Config,
|
|
118
109
|
// lifecycle
|
|
119
110
|
startCycles: tick.start,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// session fetch with its starvation backfill, session grouping, and the
|
|
4
4
|
// terminal / omitted sentinel updates.
|
|
5
5
|
import { __mixdogMemoryLog } from '../memory-log.mjs';
|
|
6
|
-
import { throwIfAborted } from '../memory-
|
|
6
|
+
import { throwIfAborted } from '../memory-cycle-shared.mjs';
|
|
7
7
|
import { CYCLE1_OMITTED_COOLDOWN_MS } from './cycle1-plan.mjs';
|
|
8
8
|
|
|
9
9
|
export function isStructurallyUnchunkableInput(row) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// through the LLM, commit each chunk as one transaction, and mark what was
|
|
4
4
|
// left out. Rows within the window are one session in chronological order.
|
|
5
5
|
import { __mixdogMemoryLog } from '../memory-log.mjs';
|
|
6
|
-
import { throwIfAborted } from '../memory-
|
|
6
|
+
import { throwIfAborted } from '../memory-cycle-shared.mjs';
|
|
7
7
|
import { assessChunkQuality, generateCycle1Chunks } from '../memory-chunk-quality.mjs';
|
|
8
8
|
import { inferChunkProjectId, syncRootEmbedding } from '../memory-embed.mjs';
|
|
9
9
|
import { isStructurallyUnchunkableInput, markOmittedRows, markTerminalRows, selectRootId } from './cycle1-rows.mjs';
|
|
@@ -42,7 +42,7 @@ async function commitCycle1Chunk(db, chunk, rootId, memberIds) {
|
|
|
42
42
|
`UPDATE entries
|
|
43
43
|
SET chunk_root = $1, is_root = 1, element = $2, category = $3, summary = $4,
|
|
44
44
|
status = 'pending', project_id = $5,
|
|
45
|
-
last_seen_at = $7, chunk_quality = $8::jsonb,
|
|
45
|
+
last_seen_at = $7, chunk_quality = $8::jsonb, duplicate_of = NULL
|
|
46
46
|
WHERE id = $6`,
|
|
47
47
|
[rootId, element, category, summary, projectId, rootId, Date.now(), JSON.stringify(quality)]
|
|
48
48
|
);
|
|
@@ -60,7 +60,6 @@ export function createLifecycleRoutes({
|
|
|
60
60
|
active_roots: stats.active_roots,
|
|
61
61
|
archived_roots: stats.archived_roots,
|
|
62
62
|
unchunked_leaves: stats.unchunked_leaves,
|
|
63
|
-
cycle2_pending_roots: stats.cycle2_pending_roots,
|
|
64
63
|
core_entries: stats.core_entries,
|
|
65
64
|
core_embed_null: stats.core_embed_null,
|
|
66
65
|
cycle_running: cycleScheduler.getCycleRunning(),
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* memory-action-handlers/cycle-actions.mjs — the cycle-driven memory actions:
|
|
3
|
-
* cycle1,
|
|
4
|
-
* primitives
|
|
3
|
+
* cycle1, flush, rebuild and backfill. Cycle scheduler
|
|
4
|
+
* primitives are injected; the whole-action
|
|
5
5
|
* backfill mutex lives here since it only guards this module's backfill path.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import { throwIfAborted } from '../memory-
|
|
7
|
+
import { flushSearchEmbeddings } from '../memory-cycle.mjs';
|
|
8
|
+
import { throwIfAborted } from '../memory-cycle-shared.mjs';
|
|
9
9
|
import { createBackfillAction } from './cycle-backfill-action.mjs';
|
|
10
10
|
import { createRebuildAction } from './cycle-rebuild-action.mjs';
|
|
11
11
|
|
|
@@ -56,41 +56,15 @@ function cycle1SummaryText(result) {
|
|
|
56
56
|
);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function cycle2SummaryResult(result) {
|
|
60
|
-
const counts = {
|
|
61
|
-
processed: result?.processed || 0,
|
|
62
|
-
merged: result?.merged || 0,
|
|
63
|
-
linked: result?.linked || 0,
|
|
64
|
-
kept: result?.kept || 0,
|
|
65
|
-
held: result?.held || 0,
|
|
66
|
-
deferred: result?.deferred || 0,
|
|
67
|
-
};
|
|
68
|
-
const parts = Object.entries(counts)
|
|
69
|
-
.filter(([, v]) => v > 0)
|
|
70
|
-
.map(([k, v]) => `${k}=${v}`);
|
|
71
|
-
if (result?.ok === false)
|
|
72
|
-
return { text: `cycle2 failed: ${result.error || 'unknown'} ${parts.join(' ')}`.trim(), isError: true };
|
|
73
|
-
if (parts.length) return { text: `cycle2 ${parts.join(' ')}` };
|
|
74
|
-
// No applied counts — distinguish an in-flight skip from an empty queue.
|
|
75
|
-
let cause = '';
|
|
76
|
-
if (result?.skippedInFlight) cause = ' (skipped: in-flight)';
|
|
77
|
-
return { text: `cycle2 noop${cause}` };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
59
|
export function createCycleActions({
|
|
81
60
|
getDb,
|
|
82
61
|
dataDir,
|
|
83
62
|
awaitCycle1Run,
|
|
84
63
|
startCycle1Run,
|
|
85
|
-
finalizeCycle2Run,
|
|
86
64
|
getSchedulerCycle1InFlight,
|
|
87
|
-
getCycle2CallLlm,
|
|
88
65
|
ingestTranscriptFile,
|
|
89
66
|
cwdFromTranscriptPath,
|
|
90
67
|
}) {
|
|
91
|
-
const withCycle2Llm = (options) =>
|
|
92
|
-
typeof options.callLlm === 'function' ? options : { ...options, callLlm: getCycle2CallLlm() };
|
|
93
|
-
|
|
94
68
|
async function cycle1(args, config, signal) {
|
|
95
69
|
const cycle1Config = cycle1ConfigFromArgs(args, config?.cycle1 || {});
|
|
96
70
|
const callerDeadlineMs = Number(args?._callerDeadlineMs) || 0;
|
|
@@ -104,50 +78,31 @@ export function createCycleActions({
|
|
|
104
78
|
return { ...result, text: cycle1SummaryText(result) };
|
|
105
79
|
}
|
|
106
80
|
|
|
107
|
-
async function cycle2(args, config, signal) {
|
|
108
|
-
const db = getDb();
|
|
109
|
-
throwIfAborted(signal);
|
|
110
|
-
const cycle2Config = { ...(config?.cycle2 || {}) };
|
|
111
|
-
if (Number.isFinite(Number(args?.batch_size))) {
|
|
112
|
-
cycle2Config.batch_size = Math.max(1, Math.floor(Number(args.batch_size)));
|
|
113
|
-
}
|
|
114
|
-
const result = await runCycle2(db, cycle2Config, withCycle2Llm({ signal }));
|
|
115
|
-
throwIfAborted(signal);
|
|
116
|
-
await finalizeCycle2Run(result);
|
|
117
|
-
return cycle2SummaryResult(result);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
81
|
async function flush(_args, config, signal) {
|
|
121
82
|
const db = getDb();
|
|
122
83
|
throwIfAborted(signal);
|
|
123
84
|
const r1 = await awaitCycle1Run(config?.cycle1 || {}, { signal });
|
|
124
85
|
throwIfAborted(signal);
|
|
125
|
-
const
|
|
86
|
+
const embeddings = await flushSearchEmbeddings(db, { signal });
|
|
126
87
|
throwIfAborted(signal);
|
|
127
|
-
await finalizeCycle2Run(r2);
|
|
128
88
|
return {
|
|
129
|
-
text: `flush: cycle1 chunks=${r1.chunks} processed=${r1.processed},
|
|
130
|
-
isError: r2.ok === false,
|
|
89
|
+
text: `flush: cycle1 chunks=${r1.chunks} processed=${r1.processed}, embeddings=${embeddings.succeeded}`,
|
|
131
90
|
};
|
|
132
91
|
}
|
|
133
92
|
|
|
134
93
|
const rebuild = createRebuildAction({
|
|
135
94
|
getDb,
|
|
136
95
|
startCycle1Run,
|
|
137
|
-
finalizeCycle2Run,
|
|
138
96
|
getSchedulerCycle1InFlight,
|
|
139
|
-
withCycle2Llm,
|
|
140
97
|
});
|
|
141
98
|
|
|
142
99
|
const backfill = createBackfillAction({
|
|
143
100
|
getDb,
|
|
144
101
|
dataDir,
|
|
145
102
|
awaitCycle1Run,
|
|
146
|
-
finalizeCycle2Run,
|
|
147
|
-
withCycle2Llm,
|
|
148
103
|
ingestTranscriptFile,
|
|
149
104
|
cwdFromTranscriptPath,
|
|
150
105
|
});
|
|
151
106
|
|
|
152
|
-
return { cycle1,
|
|
107
|
+
return { cycle1, flush, rebuild, backfill };
|
|
153
108
|
}
|
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* memory-action-handlers/cycle-backfill-action.mjs — the backfill action: one
|
|
3
3
|
* driver run over a transcript window, with the whole-action mutex and the
|
|
4
|
-
* per-iteration cancel checkpoints the driver's cycle1
|
|
4
|
+
* per-iteration cancel checkpoints the driver's cycle1 callback needs.
|
|
5
5
|
*/
|
|
6
|
-
import { runCycle2 } from '../memory-cycle.mjs';
|
|
7
6
|
import { runFullBackfill } from '../memory-ops-policy.mjs';
|
|
8
|
-
import { throwIfAborted } from '../memory-
|
|
7
|
+
import { throwIfAborted } from '../memory-cycle-shared.mjs';
|
|
9
8
|
|
|
10
9
|
export function createBackfillAction({
|
|
11
10
|
getDb,
|
|
12
11
|
dataDir,
|
|
13
12
|
awaitCycle1Run,
|
|
14
|
-
finalizeCycle2Run,
|
|
15
|
-
withCycle2Llm,
|
|
16
13
|
ingestTranscriptFile,
|
|
17
14
|
cwdFromTranscriptPath,
|
|
18
15
|
}) {
|
|
19
16
|
// Whole-action backfill mutex (transport-agnostic). memory-cycle1's
|
|
20
17
|
// _runCycle1InFlight only protects cycle1; ingest workers
|
|
21
|
-
// (memory-ops-policy.mjs)
|
|
18
|
+
// (memory-ops-policy.mjs) can still overlap if a second backfill
|
|
22
19
|
// kicks in (timeout-retry, parallel callers, /api/tool vs /mcp vs
|
|
23
20
|
// /admin/backfill). Track the in-flight promise here and reject overlaps
|
|
24
21
|
// with 409.
|
|
@@ -35,10 +32,6 @@ export function createBackfillAction({
|
|
|
35
32
|
const window = args.window != null ? String(args.window) : '7d';
|
|
36
33
|
const scope = args.scope != null ? String(args.scope) : 'all';
|
|
37
34
|
const limit = args.limit != null ? Math.max(1, Number(args.limit)) : null;
|
|
38
|
-
// Capture the cycle2 envelope so it routes through finalizeCycle2Run
|
|
39
|
-
// (which records cycle2_last_error and clears scheduler delay only on
|
|
40
|
-
// ok:true) rather than stamping cycle2 unconditionally afterward.
|
|
41
|
-
let capturedCycle2;
|
|
42
35
|
const promise = runFullBackfill(db, {
|
|
43
36
|
signal,
|
|
44
37
|
window,
|
|
@@ -48,21 +41,15 @@ export function createBackfillAction({
|
|
|
48
41
|
dataDir,
|
|
49
42
|
ingestTranscriptFile,
|
|
50
43
|
cwdFromTranscriptPath,
|
|
51
|
-
// Re-check the IPC cancel signal at every cycle1
|
|
44
|
+
// Re-check the IPC cancel signal at every cycle1 iteration the
|
|
52
45
|
// backfill driver dispatches. handleMemoryAction only checks once
|
|
53
46
|
// before dispatch; without per-iteration checkpoints a long-running
|
|
54
|
-
// backfill keeps spinning through ingest + cycle1
|
|
47
|
+
// backfill keeps spinning through ingest + cycle1 batches
|
|
55
48
|
// after the proxy has already responded "cancelled" to the caller.
|
|
56
49
|
runCycle1: (_dbArg, cycle1Config = {}, options = {}, _dir) => {
|
|
57
50
|
throwIfAborted(signal);
|
|
58
51
|
return awaitCycle1Run(cycle1Config, { ...options, signal });
|
|
59
52
|
},
|
|
60
|
-
runCycle2: async (dbArg, c2Config, c2Options) => {
|
|
61
|
-
throwIfAborted(signal);
|
|
62
|
-
const r2 = await runCycle2(dbArg, c2Config, withCycle2Llm({ ...c2Options, signal }));
|
|
63
|
-
capturedCycle2 = r2;
|
|
64
|
-
return r2;
|
|
65
|
-
},
|
|
66
53
|
});
|
|
67
54
|
backfillInFlight = promise;
|
|
68
55
|
let result;
|
|
@@ -72,11 +59,8 @@ export function createBackfillAction({
|
|
|
72
59
|
if (backfillInFlight === promise) backfillInFlight = null;
|
|
73
60
|
}
|
|
74
61
|
throwIfAborted(signal);
|
|
75
|
-
if (capturedCycle2) {
|
|
76
|
-
await finalizeCycle2Run(capturedCycle2);
|
|
77
|
-
}
|
|
78
62
|
return {
|
|
79
|
-
text: `backfill: window=${result.window} scope=${result.scope} files=${result.files} ingested=${result.ingested} cycle1_iters=${result.cycle1_iters}
|
|
63
|
+
text: `backfill: window=${result.window} scope=${result.scope} files=${result.files} ingested=${result.ingested} cycle1_iters=${result.cycle1_iters} unclassified=${result.unclassified}${result.error ? ` error=${result.error}` : ''}`,
|
|
80
64
|
isError: result.ok === false,
|
|
81
65
|
};
|
|
82
66
|
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* memory-action-handlers/cycle-rebuild-action.mjs — the destructive rebuild:
|
|
3
3
|
* drain whatever cycle1 is still running, truncate every classification
|
|
4
|
-
* column in one transaction, then re-run cycle1
|
|
4
|
+
* column in one transaction, then re-run cycle1 over the reset
|
|
5
5
|
* rows. The confirm phrase is the only guard the caller gets.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { flushSearchEmbeddings } from '../memory-cycle.mjs';
|
|
8
8
|
import { getInFlightCycle1 } from '../memory-cycle1.mjs';
|
|
9
|
-
import { throwIfAborted } from '../memory-
|
|
9
|
+
import { throwIfAborted } from '../memory-cycle-shared.mjs';
|
|
10
10
|
|
|
11
11
|
// Every root-classification column, cleared before demotion. Cleanup must run
|
|
12
12
|
// BEFORE demotion: demoting normal roots (chunk_root = id) first and then
|
|
@@ -18,7 +18,7 @@ const REBUILD_RESET_ROOTS = `
|
|
|
18
18
|
SET element = NULL, category = NULL, summary = NULL,
|
|
19
19
|
status = 'pending', score = NULL, last_seen_at = NULL,
|
|
20
20
|
embedding = NULL, summary_hash = NULL,
|
|
21
|
-
reviewed_at = NULL,
|
|
21
|
+
reviewed_at = NULL, duplicate_of = NULL,
|
|
22
22
|
error_count = 0
|
|
23
23
|
WHERE is_root = 1
|
|
24
24
|
`;
|
|
@@ -28,7 +28,7 @@ const REBUILD_RESET_LEAVES = `
|
|
|
28
28
|
element = NULL, category = NULL, summary = NULL,
|
|
29
29
|
score = NULL, last_seen_at = NULL,
|
|
30
30
|
embedding = NULL, summary_hash = NULL,
|
|
31
|
-
reviewed_at = NULL,
|
|
31
|
+
reviewed_at = NULL, duplicate_of = NULL,
|
|
32
32
|
error_count = 0
|
|
33
33
|
WHERE is_root = 0
|
|
34
34
|
`;
|
|
@@ -52,18 +52,12 @@ async function drainCycle1(db, getSchedulerCycle1InFlight) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export function createRebuildAction({
|
|
56
|
-
getDb,
|
|
57
|
-
startCycle1Run,
|
|
58
|
-
finalizeCycle2Run,
|
|
59
|
-
getSchedulerCycle1InFlight,
|
|
60
|
-
withCycle2Llm,
|
|
61
|
-
}) {
|
|
55
|
+
export function createRebuildAction({ getDb, startCycle1Run, getSchedulerCycle1InFlight }) {
|
|
62
56
|
return async function rebuild(args, config, signal) {
|
|
63
57
|
const db = getDb();
|
|
64
58
|
if (args.confirm !== 'REBUILD MEMORY') {
|
|
65
59
|
return {
|
|
66
|
-
text: 'rebuild requires confirm: "REBUILD MEMORY" (truncates classification columns and re-runs
|
|
60
|
+
text: 'rebuild requires confirm: "REBUILD MEMORY" (truncates classification columns and re-runs summarization)',
|
|
67
61
|
isError: true,
|
|
68
62
|
};
|
|
69
63
|
}
|
|
@@ -84,11 +78,10 @@ export function createRebuildAction({
|
|
|
84
78
|
// and guarantees the newly demoted rows are read.
|
|
85
79
|
const r1 = await startCycle1Run(config?.cycle1 || {}, { signal });
|
|
86
80
|
throwIfAborted(signal);
|
|
87
|
-
const
|
|
88
|
-
|
|
81
|
+
const embeddings = await flushSearchEmbeddings(db, { signal });
|
|
82
|
+
throwIfAborted(signal);
|
|
89
83
|
return {
|
|
90
|
-
text: `rebuild: cycle1 chunks=${r1.chunks} processed=${r1.processed},
|
|
91
|
-
isError: r2.ok === false,
|
|
84
|
+
text: `rebuild: cycle1 chunks=${r1.chunks} processed=${r1.processed}, embeddings=${embeddings.succeeded}`,
|
|
92
85
|
};
|
|
93
86
|
};
|
|
94
87
|
}
|
|
@@ -29,15 +29,13 @@ export function createMaintenanceActions({ getDb, entryStats, getCycleLastRun })
|
|
|
29
29
|
const { dims, dimsErr } = await embeddingDims(db);
|
|
30
30
|
const bootstrapComplete = await isBootstrapComplete(db);
|
|
31
31
|
const lines = [
|
|
32
|
-
`entries: total=${stats.total} roots=${stats.roots} cycle1_raw=${stats.unchunked_leaves} (unchunked leaves)
|
|
32
|
+
`entries: total=${stats.total} roots=${stats.roots} cycle1_raw=${stats.unchunked_leaves} (unchunked leaves)`,
|
|
33
33
|
`status: ${stats.byStatus.map((r) => `${r.status ?? '?'}:${r.c}`).join(', ') || 'empty'}`,
|
|
34
34
|
`categories: ${stats.byCategory.map((r) => `${r.category ?? 'NULL'}:${r.c}`).join(', ') || 'empty'}`,
|
|
35
35
|
`core_memory: user=${stats.core_entries} embed_null=${stats.core_embed_null}`,
|
|
36
36
|
`embedding_index: ready dims=${dims}${dimsErr ? ` (meta_read_error: ${dimsErr})` : ''}`,
|
|
37
37
|
`bootstrap: ${bootstrapComplete ? 'complete' : 'incomplete'}`,
|
|
38
38
|
`last_cycle1: ${agoText(last.cycle1)}`,
|
|
39
|
-
`last_cycle2: ${agoText(last.cycle2)}`,
|
|
40
|
-
...(last.cycle2_last_error ? [`last_cycle2_error: ${last.cycle2_last_error}`] : []),
|
|
41
39
|
];
|
|
42
40
|
return { text: lines.join('\n') };
|
|
43
41
|
}
|
|
@@ -154,14 +154,12 @@ export function createManageActions({ getDb, log }) {
|
|
|
154
154
|
await db.transaction(async (tx) => {
|
|
155
155
|
// Editing either side invalidates the duplicate equivalence, not
|
|
156
156
|
// the original chunks or their lineage.
|
|
157
|
-
await tx.query(`UPDATE entries SET duplicate_of = NULL
|
|
158
|
-
id,
|
|
159
|
-
]);
|
|
157
|
+
await tx.query(`UPDATE entries SET duplicate_of = NULL WHERE duplicate_of = $1`, [id]);
|
|
160
158
|
await tx.query(
|
|
161
159
|
`
|
|
162
160
|
UPDATE entries
|
|
163
161
|
SET element = $1, summary = $2, category = $3, score = $4,
|
|
164
|
-
last_seen_at = $5, content = $6,
|
|
162
|
+
last_seen_at = $5, content = $6, duplicate_of = NULL
|
|
165
163
|
WHERE id = $7
|
|
166
164
|
`,
|
|
167
165
|
[finalElement, finalSummary, finalCategory, score, nowMs, composedContent, id]
|