mixdog 1.0.4 → 1.0.5
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 +10 -5
- 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
|
@@ -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]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//
|
|
3
3
|
// The write/maintenance action cluster and the `memory`/`search_memories`/
|
|
4
4
|
// `recall` tool dispatch. Actions are grouped by responsibility under
|
|
5
|
-
// memory-action-handlers/: cycle-driven (cycle1/
|
|
5
|
+
// memory-action-handlers/: cycle-driven (cycle1/flush/rebuild/
|
|
6
6
|
// backfill), maintenance (status/prune/purge), `manage` (generated-history
|
|
7
7
|
// roots) and `core` (user-curated entries). Live DB handle, config reader,
|
|
8
8
|
// cycle scheduler primitives, cycle-LLM adapters, query handlers, and the
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// `db`, the scheduler, and lifecycle state.
|
|
11
11
|
|
|
12
12
|
import { createToolCallHandler } from './tool-call-handler.mjs';
|
|
13
|
-
import { throwIfAborted } from './memory-
|
|
13
|
+
import { throwIfAborted } from './memory-cycle-shared.mjs';
|
|
14
14
|
import { createCycleActions } from './memory-action-handlers/cycle-actions.mjs';
|
|
15
15
|
import { createMaintenanceActions } from './memory-action-handlers/maintenance-actions.mjs';
|
|
16
16
|
import { createManageActions } from './memory-action-handlers/manage-actions.mjs';
|
|
@@ -28,8 +28,6 @@ export function createMemoryActionHandlers(deps) {
|
|
|
28
28
|
const actions = {
|
|
29
29
|
status: maintenance.status,
|
|
30
30
|
cycle1: cycle.cycle1,
|
|
31
|
-
cycle2: cycle.cycle2,
|
|
32
|
-
sleep: cycle.cycle2,
|
|
33
31
|
// Direct semantic-search surface for callers that want raw ranked rows
|
|
34
32
|
// without going through the Lead-side recall synthesizer: the
|
|
35
33
|
// handleSearch executor is exposed through the public `memory` tool
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
// Shared
|
|
2
|
-
// concurrency and store faults.
|
|
3
|
-
// No cycle2 business logic; safe to import from any cycle2 sub-module.
|
|
1
|
+
// Shared memory helpers: logging, cancellation, concurrency and store faults.
|
|
4
2
|
|
|
5
3
|
import { __mixdogMemoryLog } from './memory-log.mjs';
|
|
6
4
|
export { __mixdogMemoryLog };
|
|
@@ -9,8 +7,13 @@ export function throwIfAborted(signal) {
|
|
|
9
7
|
if (signal?.aborted) throw signal.reason ?? new Error('aborted');
|
|
10
8
|
}
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
export function parseInterval(value) {
|
|
11
|
+
const match = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/.exec(String(value).trim());
|
|
12
|
+
if (!match) throw new Error(`[memory-cycle] invalid interval config: ${value}`);
|
|
13
|
+
return Number(match[1]) * { ms: 1, s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 }[match[2]];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Bounds concurrent summarization windows.
|
|
14
17
|
export function createSemaphore(limit) {
|
|
15
18
|
const cap = Math.max(1, Number(limit) || 1);
|
|
16
19
|
let active = 0;
|
|
@@ -31,12 +34,11 @@ export function createSemaphore(limit) {
|
|
|
31
34
|
};
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
//
|
|
35
|
-
// confused:
|
|
37
|
+
// Store failures must not be confused with rejected or cancelled work:
|
|
36
38
|
// * STORE FAULT — the database itself failed the write (transaction rolled
|
|
37
|
-
// back, or its COMMIT outcome is unknown).
|
|
38
|
-
//
|
|
39
|
-
// *
|
|
39
|
+
// back, or its COMMIT outcome is unknown). The store's state is no longer
|
|
40
|
+
// known, so the run stops.
|
|
41
|
+
// * rejection — a guard refused the mutation (stale snapshot, status
|
|
40
42
|
// moved, content changed). The store is healthy;
|
|
41
43
|
// these return normally and are counted as ordinary rejections/errors.
|
|
42
44
|
// Only writers raise store faults, via markStoreFault; callers branch on
|
|
@@ -49,12 +51,8 @@ export function createSemaphore(limit) {
|
|
|
49
51
|
// reclassified because of how its text happens to read, and a store fault keeps
|
|
50
52
|
// the original message verbatim so logs stay honest.
|
|
51
53
|
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
// same process, same module registry, same
|
|
55
|
-
// tick. runCycle2 converts it at its own boundary into a plain
|
|
56
|
-
// { ok: false, error: <string>, storeFault: <boolean> } result, so the explicit
|
|
57
|
-
// boolean — not a re-parsed Error — is what any IPC/worker hop carries onward.
|
|
54
|
+
// Embedding writers use this classification to retain ambiguous commit and
|
|
55
|
+
// rollback failures without disguising them as an empty successful flush.
|
|
58
56
|
export const MEMORY_STORE_FAULT_CODE = 'MEMORY_STORE_FAULT';
|
|
59
57
|
|
|
60
58
|
export class MemoryStoreFault extends Error {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
// Search-history maintenance: summarization and
|
|
1
|
+
// Search-history maintenance: summarization and embedding maintenance.
|
|
2
2
|
export {
|
|
3
3
|
syncRootEmbedding,
|
|
4
4
|
flushEmbeddingDirty,
|
|
5
|
+
flushSearchEmbeddings,
|
|
5
6
|
flushRawEmbeddings,
|
|
6
7
|
inferChunkProjectId,
|
|
7
8
|
} from './memory-embed.mjs';
|
|
8
9
|
export { runCycle1 } from './memory-cycle1.mjs';
|
|
9
|
-
export {
|
|
10
|
+
export { parseInterval } from './memory-cycle-shared.mjs';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// the advisory lock and request coalescing; _runCycle1Impl orchestrates one
|
|
3
3
|
// run out of the cycle1/ modules (plan, rows, window, result).
|
|
4
4
|
import { __mixdogMemoryLog } from './memory-log.mjs';
|
|
5
|
-
import { createSemaphore, throwIfAborted } from './memory-
|
|
5
|
+
import { createSemaphore, throwIfAborted } from './memory-cycle-shared.mjs';
|
|
6
6
|
|
|
7
7
|
import { CYCLE1_INPUT_TOKEN_BUDGET, cycle1SourceBudget, partitionCycle1Rows } from './memory-chunk-quality.mjs';
|
|
8
8
|
import { callAgentDispatch } from './agent-ipc.mjs';
|
|
@@ -4,7 +4,7 @@ import { embedTexts, getEmbeddingModelId, holdEmbeddingWarm } from './embedding-
|
|
|
4
4
|
import { embeddingToSql } from './memory.mjs';
|
|
5
5
|
import { createHash } from 'node:crypto';
|
|
6
6
|
import { pruneEmbeddingCache, resolveEmbeddingCacheMaxRows } from './embedding-cache-retention.mjs';
|
|
7
|
-
import { throwIfAborted, markStoreFault } from './memory-
|
|
7
|
+
import { throwIfAborted, markStoreFault } from './memory-cycle-shared.mjs';
|
|
8
8
|
|
|
9
9
|
// Restart-survivable embedding dedup cache (DDL created on first flush).
|
|
10
10
|
// Keyed per-db handle so a second DB instance in the same process re-runs the
|
|
@@ -635,6 +635,19 @@ async function syncBatchEmbeddings(db, ids, options = {}) {
|
|
|
635
635
|
return writtenIds;
|
|
636
636
|
}
|
|
637
637
|
|
|
638
|
+
// Explicit maintenance must propagate partial failures and caller cancellation,
|
|
639
|
+
// including callers sharing a flush that was started without their signal.
|
|
640
|
+
export async function flushSearchEmbeddings(db, options = {}) {
|
|
641
|
+
const result = await flushEmbeddingDirty(db, options);
|
|
642
|
+
throwIfAborted(options.signal);
|
|
643
|
+
if (result?.timedOut || result?.failed?.length) {
|
|
644
|
+
throw new Error(
|
|
645
|
+
`embedding maintenance incomplete: failed=${result.failed?.length || 0} timedOut=${Boolean(result.timedOut)}`
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
return result;
|
|
649
|
+
}
|
|
650
|
+
|
|
638
651
|
// Embeds one root; true when its fresh vector was written.
|
|
639
652
|
export async function syncRootEmbedding(db, rootId, options = {}) {
|
|
640
653
|
const writtenIds = await syncBatchEmbeddings(db, [rootId], options);
|
|
@@ -3,7 +3,8 @@ import { __mixdogMemoryLog } from './memory-log.mjs';
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { mixdogHome } from '../../shared/plugin-paths.mjs';
|
|
6
|
-
import { throwIfAborted } from './memory-
|
|
6
|
+
import { throwIfAborted } from './memory-cycle-shared.mjs';
|
|
7
|
+
import { flushSearchEmbeddings } from './memory-embed.mjs';
|
|
7
8
|
import { isSkippedWatchPath, isTranscriptJsonlName } from './ingest/transcript-discovery.mjs';
|
|
8
9
|
|
|
9
10
|
function normalizeBackfillWindow(value) {
|
|
@@ -80,7 +81,7 @@ export async function runFullBackfill(
|
|
|
80
81
|
ingestTranscriptFile,
|
|
81
82
|
cwdFromTranscriptPath,
|
|
82
83
|
runCycle1,
|
|
83
|
-
|
|
84
|
+
flushEmbeddings = flushSearchEmbeddings,
|
|
84
85
|
now = Date.now(),
|
|
85
86
|
projectsRoot = null,
|
|
86
87
|
workspaceCwd = null,
|
|
@@ -91,8 +92,8 @@ export async function runFullBackfill(
|
|
|
91
92
|
if (typeof ingestTranscriptFile !== 'function') {
|
|
92
93
|
throw new Error('runFullBackfill: ingestTranscriptFile required');
|
|
93
94
|
}
|
|
94
|
-
if (typeof runCycle1 !== 'function'
|
|
95
|
-
throw new Error('runFullBackfill: runCycle1
|
|
95
|
+
if (typeof runCycle1 !== 'function') {
|
|
96
|
+
throw new Error('runFullBackfill: runCycle1 required');
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
const normalizedWindow = normalizeBackfillWindow(window);
|
|
@@ -158,16 +159,13 @@ export async function runFullBackfill(
|
|
|
158
159
|
prevUnclassified = nextUnclassified;
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
let reviewed = 0;
|
|
162
162
|
try {
|
|
163
163
|
throwIfAborted(signal);
|
|
164
|
-
|
|
165
|
-
reviewed = Number(c2?.processed ?? 0);
|
|
166
|
-
if (c2?.ok === false) throw new Error(c2.error || 'cycle2 failed');
|
|
164
|
+
await flushEmbeddings(db, { signal });
|
|
167
165
|
} catch (err) {
|
|
168
166
|
throwIfAborted(signal);
|
|
169
|
-
errors.push({ stage: '
|
|
170
|
-
__mixdogMemoryLog(`[backfill]
|
|
167
|
+
errors.push({ stage: 'embedding', error: err.message });
|
|
168
|
+
__mixdogMemoryLog(`[backfill] embedding error: ${err.message}\n`);
|
|
171
169
|
}
|
|
172
170
|
|
|
173
171
|
const unclassified = await countUnclassified(db);
|
|
@@ -179,7 +177,6 @@ export async function runFullBackfill(
|
|
|
179
177
|
files: selected.length,
|
|
180
178
|
ingested,
|
|
181
179
|
cycle1_iters: cycle1Iters,
|
|
182
|
-
reviewed,
|
|
183
180
|
unclassified,
|
|
184
181
|
};
|
|
185
182
|
}
|
|
@@ -265,18 +265,14 @@ export async function ensureCurrentSchemaExtensions(db, dims, embeddingIdentity
|
|
|
265
265
|
);
|
|
266
266
|
}
|
|
267
267
|
await db.exec(`ALTER TABLE entries ADD COLUMN IF NOT EXISTS chunk_quality jsonb`);
|
|
268
|
-
//
|
|
269
|
-
//
|
|
270
|
-
await db.exec(`ALTER TABLE entries ADD COLUMN IF NOT EXISTS cycle2_reviewed_at bigint`);
|
|
268
|
+
// Existing retired review metadata is left untouched, but no longer created.
|
|
269
|
+
// Preserve the search relationships used by recall.
|
|
271
270
|
await db.exec(
|
|
272
271
|
`ALTER TABLE entries ADD COLUMN IF NOT EXISTS duplicate_of bigint REFERENCES entries(id) ON DELETE SET NULL`
|
|
273
272
|
);
|
|
274
273
|
await db.exec(
|
|
275
274
|
`CREATE INDEX IF NOT EXISTS idx_entries_duplicate_of ON entries(duplicate_of) WHERE duplicate_of IS NOT NULL`
|
|
276
275
|
);
|
|
277
|
-
await db.exec(
|
|
278
|
-
`CREATE INDEX IF NOT EXISTS idx_entries_cycle2_unreviewed ON entries(ts DESC, id DESC) WHERE is_root = 1 AND cycle2_reviewed_at IS NULL`
|
|
279
|
-
);
|
|
280
276
|
await db.exec(`ALTER TABLE entries ADD COLUMN IF NOT EXISTS time_source text`);
|
|
281
277
|
await db.exec(`ALTER TABLE entries ADD COLUMN IF NOT EXISTS concept_id bigint`);
|
|
282
278
|
await db.exec(`ALTER TABLE entries ADD COLUMN IF NOT EXISTS supersedes_id bigint`);
|
|
@@ -50,7 +50,7 @@ function installPoolErrorHandler(pool, label, { onConnectionLoss } = {}) {
|
|
|
50
50
|
const logRecoveryFailure = (recoverErr) =>
|
|
51
51
|
__mixdogMemoryLog(`[pg-adapter] ${label} client-error recovery failed: ${recoverErr?.message || recoverErr}\n`);
|
|
52
52
|
// pg-pool deliberately removes its idle error listener while a Client is
|
|
53
|
-
// checked out. Long-running advisory-lock owners (cycle1
|
|
53
|
+
// checked out. Long-running advisory-lock owners (cycle1) can therefore
|
|
54
54
|
// receive a socket-end `error` between queries with no listener at all,
|
|
55
55
|
// which Node treats as an uncaught exception. Give every physical Client a
|
|
56
56
|
// permanent last-resort listener; pg-pool's own idle listener still owns
|
|
@@ -26,7 +26,7 @@ import { readRawRowsInWindow } from './query-raw-window.mjs';
|
|
|
26
26
|
import { recallSessionRows } from './query-session-recall.mjs';
|
|
27
27
|
import { recallCoreRows } from './query-core-recall.mjs';
|
|
28
28
|
import { browseEntries } from './query-window-browse.mjs';
|
|
29
|
-
import { throwIfAborted } from './memory-
|
|
29
|
+
import { throwIfAborted } from './memory-cycle-shared.mjs';
|
|
30
30
|
|
|
31
31
|
/** Cold-recall log throttle: one line per 10s window per memory runtime. */
|
|
32
32
|
function createColdRecallNote(log) {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import { searchRelevantHybrid } from './memory-recall-store.mjs';
|
|
12
12
|
import { retrieveEntries } from './memory-retrievers.mjs';
|
|
13
13
|
import { compareRecallByScore, compareRecallNewestFirst } from './recall-order.mjs';
|
|
14
|
-
import { throwIfAborted } from './memory-
|
|
14
|
+
import { throwIfAborted } from './memory-cycle-shared.mjs';
|
|
15
15
|
import { expandRecallEventContext } from './recall-event-context.mjs';
|
|
16
16
|
import { insertTraceEvents } from './trace-store.mjs';
|
|
17
17
|
import {
|
|
@@ -150,11 +150,6 @@ export function createQueryMaintenanceHandlers({ getDb }) {
|
|
|
150
150
|
await tx.query(`SELECT COUNT(*) c FROM entries WHERE is_root = 1 AND status = 'archived'`)
|
|
151
151
|
).rows[0].c;
|
|
152
152
|
const unchunked_leaves = (await tx.query(`SELECT COUNT(*) c FROM entries WHERE chunk_root IS NULL`)).rows[0].c;
|
|
153
|
-
const cycle2_pending_roots = (
|
|
154
|
-
await tx.query(
|
|
155
|
-
`SELECT COUNT(*) c FROM entries WHERE is_root = 1 AND cycle2_reviewed_at IS NULL AND duplicate_of IS NULL`
|
|
156
|
-
)
|
|
157
|
-
).rows[0].c;
|
|
158
153
|
const core_entries = (await tx.query(`SELECT COUNT(*) c FROM core_entries`)).rows[0].c;
|
|
159
154
|
const core_embed_null = (await tx.query(`SELECT COUNT(*) c FROM core_entries WHERE embedding IS NULL`)).rows[0].c;
|
|
160
155
|
const byStatus = (await tx.query(`SELECT status, COUNT(*) c FROM entries WHERE is_root = 1 GROUP BY status`))
|
|
@@ -168,7 +163,6 @@ export function createQueryMaintenanceHandlers({ getDb }) {
|
|
|
168
163
|
active_roots,
|
|
169
164
|
archived_roots,
|
|
170
165
|
unchunked_leaves,
|
|
171
|
-
cycle2_pending_roots,
|
|
172
166
|
core_entries,
|
|
173
167
|
core_embed_null,
|
|
174
168
|
byStatus,
|
|
@@ -307,7 +307,7 @@ function rowMembers(r, { includeRootSource, sourceWindow }) {
|
|
|
307
307
|
|
|
308
308
|
// Chunks present: each member is its own line. The root row is a grouping
|
|
309
309
|
// artifact for retrieval — the caller wants the chunk content (cycle1 raw),
|
|
310
|
-
// not the
|
|
310
|
+
// not the stored summary.
|
|
311
311
|
function memberUnits(r, members, render, preserveSource) {
|
|
312
312
|
return members.map((m, memberIndex) => {
|
|
313
313
|
const source = String(m.content ?? '');
|