memhtml 0.2.1 → 0.2.3
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 -6
- package/agent/channels/eve.ts +1 -1
- package/dist/{dist-Bubu4ZZa.mjs → dist-Dj-MYf9q.mjs} +1 -1
- package/dist/{dist-CrYVXFO2.mjs → dist-dfrcDFad.mjs} +44 -40
- package/dist/dist-dfrcDFad.mjs.map +1 -0
- package/dist/{dist-DUuomISL.mjs → dist-t84Q_98w.mjs} +22 -8
- package/dist/dist-t84Q_98w.mjs.map +1 -0
- package/dist/memhtml-mcp.mjs +16 -16
- package/dist/memhtml-mcp.mjs.map +1 -1
- package/dist/memhtml.mjs +19 -19
- package/dist/memhtml.mjs.map +1 -1
- package/package.json +8 -8
- package/src/agent-build.ts +1 -1
- package/src/client.ts +2 -2
- package/src/contract.ts +2 -2
- package/src/mount.ts +1 -1
- package/dist/dist-CrYVXFO2.mjs.map +0 -1
- package/dist/dist-DUuomISL.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -410,7 +410,7 @@ envelope. `docs/code-mode.md` is the cookbook, with a measured helper and five r
|
|
|
410
410
|
| MemoryAgentBench FactConsolidation single-hop (26KB to 1.1MB stores) | 92% to 97% | ~60% at 26KB only |
|
|
411
411
|
| MemoryAgentBench FactConsolidation multi-hop | 37% to 49% | ≤7% all methods |
|
|
412
412
|
| BEAM Contradiction Resolution (100K split, 40 probes) | 43.8% mean | 0% to 5% all systems |
|
|
413
|
-
| LongMemEval-S (
|
|
413
|
+
| LongMemEval-S (full 500, judged 2026-08-07) | 67.0% | ~55% to 65% typical agent baselines |
|
|
414
414
|
|
|
415
415
|
Read the cross-judge numbers as reference points rather than as a ranking: the judges here are verbatim
|
|
416
416
|
prompt ports running haiku-4.5, where the papers used gpt-4o and gpt-4.1-mini. `ROADMAP.md` carries these
|
|
@@ -422,7 +422,7 @@ numbers and the horizons they rank.
|
|
|
422
422
|
$MEMHTML_ROOT/ # its own git repo, one global memory store
|
|
423
423
|
projects/<workspace-slug>/ # a workspace IS a directory. There is no workspaces table.
|
|
424
424
|
areas/<area-slug>/ # ongoing responsibilities
|
|
425
|
-
areas/arcs/ #
|
|
425
|
+
areas/arcs/ # behavioral arcs (system-written by sleep only)
|
|
426
426
|
areas/inbox/ # where an unplaceable memory lands
|
|
427
427
|
resources/<topic>/
|
|
428
428
|
resources/people/<person>.html # the person plane
|
|
@@ -441,10 +441,12 @@ The layering is strict and TypeScript project references enforce it. `@memhtml/c
|
|
|
441
441
|
`@memhtml/domain` import `effect` and nothing else, and a test reads `domain`'s own `dist` to confirm it
|
|
442
442
|
names no database driver, no SDK, and no `node:fs`.
|
|
443
443
|
|
|
444
|
-
None of them is published.
|
|
445
|
-
the
|
|
446
|
-
|
|
447
|
-
|
|
444
|
+
None of them is published. Every workspace package is `private`, and `mise run package:assemble`
|
|
445
|
+
bundles the libraries and the binary-bearing apps into the single `memhtml` package that carries the
|
|
446
|
+
two binaries — the docs site and the integration-test harness stay outside the bundle
|
|
447
|
+
(`tsdown.config.ts` names the exact set). The table below is a map of the source, not a list of
|
|
448
|
+
things to install. `RELEASING.md` covers how the artifact is built and what must stay outside the
|
|
449
|
+
bundle.
|
|
448
450
|
|
|
449
451
|
| Package | What it owns |
|
|
450
452
|
|---|---|
|
|
@@ -459,6 +461,8 @@ outside the bundle.
|
|
|
459
461
|
| `@memhtml/eval` | The fixture corpus generator and the refusable discrimination gate. |
|
|
460
462
|
| `@memhtml/cli` | The `memhtml` binary, the envelope contract, and the one composition root. |
|
|
461
463
|
| `@memhtml/mcp` | The `memhtml-mcp` stdio server: 14 tools, 2 resources. |
|
|
464
|
+
| `@memhtml/consolidator` | The sandboxed eve agent that distills candidate memories from raw transcripts. |
|
|
465
|
+
| `@memhtml/docs` | The documentation site. |
|
|
462
466
|
|
|
463
467
|
## Development
|
|
464
468
|
|
package/agent/channels/eve.ts
CHANGED
|
@@ -35,7 +35,7 @@ import { runVerifierConfig } from "../../src/run-auth.js"
|
|
|
35
35
|
* and eve rejects a token with no `sub` before consulting any matcher. That is what keeps a secret
|
|
36
36
|
* leaked into some other eve app's environment from cross-authenticating here.
|
|
37
37
|
*
|
|
38
|
-
* ## The bind address STAYS, as
|
|
38
|
+
* ## The bind address STAYS, as defense in depth
|
|
39
39
|
*
|
|
40
40
|
* `eve start` binds ALL INTERFACES by default (node_modules/eve/docs/reference/cli.md, `eve start
|
|
41
41
|
* --host`), so `src/client.ts` still spawns with `--host 127.0.0.1` from a constant that takes no
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as MAX_QUOTE_CHARS, C as ConsolidationResult, D as ConsolidatorUnavailable, E as ConsolidatorRunFailed, F as toJsonSchema, I as ungroundedEvidenceReason, M as credentialsMissingReason, N as hasConsolidatorCredentials, O as MAX_CLAIM_CHARS, P as isConsolidationKind, S as ConsolidationPayload, T as ConsolidatorCredentialsMissing, _ as readOnlyRootsProblem, a as RUN_SECRET_ENV, b as CandidateEvidence, c as runVerifierConfig, d as SANDBOX_MOUNTS_ENV, f as SandboxMountInvalid, g as pinCorpusSnapshot, h as mountReadOnlyRoots, i as makeConsolidator, j as MAX_TRANSCRIPTS_PER_RUN, k as MAX_GIST_CHARS, l as sameRunSecret, m as encodeSandboxMounts, n as consolidatorLive, o as mintRunSecret, p as decodeSandboxMounts, r as guestPathFor, s as runSecretFrom, t as Consolidator, u as signRunToken, v as CONSOLIDATION_KINDS, w as ConsolidatorContractViolation, x as CandidateMemory, y as CONSOLIDATION_OUTPUT_JSON_SCHEMA } from "./dist-
|
|
1
|
+
import { A as MAX_QUOTE_CHARS, C as ConsolidationResult, D as ConsolidatorUnavailable, E as ConsolidatorRunFailed, F as toJsonSchema, I as ungroundedEvidenceReason, M as credentialsMissingReason, N as hasConsolidatorCredentials, O as MAX_CLAIM_CHARS, P as isConsolidationKind, S as ConsolidationPayload, T as ConsolidatorCredentialsMissing, _ as readOnlyRootsProblem, a as RUN_SECRET_ENV, b as CandidateEvidence, c as runVerifierConfig, d as SANDBOX_MOUNTS_ENV, f as SandboxMountInvalid, g as pinCorpusSnapshot, h as mountReadOnlyRoots, i as makeConsolidator, j as MAX_TRANSCRIPTS_PER_RUN, k as MAX_GIST_CHARS, l as sameRunSecret, m as encodeSandboxMounts, n as consolidatorLive, o as mintRunSecret, p as decodeSandboxMounts, r as guestPathFor, s as runSecretFrom, t as Consolidator, u as signRunToken, v as CONSOLIDATION_KINDS, w as ConsolidatorContractViolation, x as CandidateMemory, y as CONSOLIDATION_OUTPUT_JSON_SCHEMA } from "./dist-t84Q_98w.mjs";
|
|
2
2
|
|
|
3
3
|
export { CONSOLIDATION_KINDS, CONSOLIDATION_OUTPUT_JSON_SCHEMA, CandidateEvidence, CandidateMemory, ConsolidationPayload, ConsolidationResult, Consolidator, ConsolidatorContractViolation, ConsolidatorCredentialsMissing, ConsolidatorRunFailed, ConsolidatorUnavailable, MAX_CLAIM_CHARS, MAX_GIST_CHARS, MAX_QUOTE_CHARS, MAX_TRANSCRIPTS_PER_RUN, RUN_SECRET_ENV, SANDBOX_MOUNTS_ENV, SandboxMountInvalid, consolidatorLive, credentialsMissingReason, decodeSandboxMounts, encodeSandboxMounts, guestPathFor, hasConsolidatorCredentials, isConsolidationKind, makeConsolidator, mintRunSecret, mountReadOnlyRoots, pinCorpusSnapshot, readOnlyRootsProblem, runSecretFrom, runVerifierConfig, sameRunSecret, signRunToken, toJsonSchema, ungroundedEvidenceReason };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as MEMORY_EXTENSION, B as ModelUnavailable, Ct as slugify, H as StorageFailure, J as relClassFor, L as DirtyTree, Q as INBOX_DIR, R as InvalidMemory, St as filenameFor, U as WriteConflict, V as PathNotFound, W as EdgeRel, X as relTokenFor, Y as relForToken, Z as ARCS_DIR, _t as TaskStatus, at as memoryPathFor, bt as parseEntity, ct as placementFor, dt as MEMORY_TYPES, et as PEOPLE_DIR, ft as MemoryStatus, gt as TASK_STATUSES, ht as PERSON_ENTITY_PREFIX, it as isValidMemoryPath, lt as Confidence, mt as PARA_BUCKETS, nt as archivePathFor, ot as normalizePath, pt as MemoryType, q as isEdgeRel, rt as isArchivePath, st as paraBucketOf, ut as Importance, vt as WRITABLE_MEMORY_TYPES, wt as withCollisionOrdinal, xt as SLUG_FALLBACK, yt as isTaskStatus, z as LlmContractViolation } from "./dist-
|
|
1
|
+
import { $ as MEMORY_EXTENSION, B as ModelUnavailable, Ct as slugify, H as StorageFailure, J as relClassFor, L as DirtyTree, Q as INBOX_DIR, R as InvalidMemory, St as filenameFor, U as WriteConflict, V as PathNotFound, W as EdgeRel, X as relTokenFor, Y as relForToken, Z as ARCS_DIR, _t as TaskStatus, at as memoryPathFor, bt as parseEntity, ct as placementFor, dt as MEMORY_TYPES, et as PEOPLE_DIR, ft as MemoryStatus, gt as TASK_STATUSES, ht as PERSON_ENTITY_PREFIX, it as isValidMemoryPath, lt as Confidence, mt as PARA_BUCKETS, nt as archivePathFor, ot as normalizePath, pt as MemoryType, q as isEdgeRel, rt as isArchivePath, st as paraBucketOf, ut as Importance, vt as WRITABLE_MEMORY_TYPES, wt as withCollisionOrdinal, xt as SLUG_FALLBACK, yt as isTaskStatus, z as LlmContractViolation } from "./dist-t84Q_98w.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { Config, Context, Effect, Layer, Result, Schedule, Schema } from "effect";
|
|
4
4
|
import { mkdir, mkdtemp, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -327,7 +327,7 @@ const pagerank = (nodes, edges, options = {}) => {
|
|
|
327
327
|
* Communities by label propagation over the edge list read as undirected.
|
|
328
328
|
*
|
|
329
329
|
* Deterministic in place of a seed: nodes start labelled by themselves, sweeps visit them in
|
|
330
|
-
* sorted order, and a node adopts the highest-weighted
|
|
330
|
+
* sorted order, and a node adopts the highest-weighted neighboring label with the
|
|
331
331
|
* lexicographically smallest label breaking a tie. The returned labels are canonicalized to
|
|
332
332
|
* the smallest member path of each community, so the partition itself is reproducible and not
|
|
333
333
|
* only the grouping.
|
|
@@ -340,15 +340,15 @@ const labelPropagation = (nodes, edges, options = {}) => {
|
|
|
340
340
|
const { sorted, folded } = normalize$1(nodes, edges);
|
|
341
341
|
const minSize = options.minCommunitySize ?? 3;
|
|
342
342
|
const maxSweeps = options.maxSweeps ?? 100;
|
|
343
|
-
const
|
|
343
|
+
const neighbors = /* @__PURE__ */ new Map();
|
|
344
344
|
const link = (from, to, strength) => {
|
|
345
|
-
const bucket =
|
|
345
|
+
const bucket = neighbors.get(from);
|
|
346
346
|
const edge = {
|
|
347
347
|
src: from,
|
|
348
348
|
dst: to,
|
|
349
349
|
strength
|
|
350
350
|
};
|
|
351
|
-
if (bucket === void 0)
|
|
351
|
+
if (bucket === void 0) neighbors.set(from, [edge]);
|
|
352
352
|
else bucket.push(edge);
|
|
353
353
|
};
|
|
354
354
|
for (const edge of folded) {
|
|
@@ -360,7 +360,7 @@ const labelPropagation = (nodes, edges, options = {}) => {
|
|
|
360
360
|
let changed = false;
|
|
361
361
|
for (const node of sorted) {
|
|
362
362
|
const weightByLabel = /* @__PURE__ */ new Map();
|
|
363
|
-
for (const edge of
|
|
363
|
+
for (const edge of neighbors.get(node) ?? []) {
|
|
364
364
|
const label = labels.get(edge.dst);
|
|
365
365
|
if (label === void 0) continue;
|
|
366
366
|
weightByLabel.set(label, (weightByLabel.get(label) ?? 0) + edge.strength);
|
|
@@ -1874,7 +1874,7 @@ const buildProbes = (base, wanted) => {
|
|
|
1874
1874
|
* the cosine. Measured before this was fixed: the kit-free control took FTS rank 1 and vector
|
|
1875
1875
|
* rank 3 while its target sat at 4 and 10, on 22 of 36 probes. The gate was failing on
|
|
1876
1876
|
* document length instead of on the fact. A control that wins by being terser proves nothing
|
|
1877
|
-
* about discrimination, and a fold that "fixed" it would be tuned against an
|
|
1877
|
+
* about discrimination, and a fold that "fixed" it would be tuned against an artifact.
|
|
1878
1878
|
*
|
|
1879
1879
|
* With the kit copied, the pair differs by exactly the flipped token, which is the
|
|
1880
1880
|
* high-cosine wrong-fact adversary design §5 asks for.
|
|
@@ -1956,7 +1956,7 @@ const ACCESSED_FRACTION = .6;
|
|
|
1956
1956
|
* happens to be some probe's control.
|
|
1957
1957
|
* 2. **The spread is QUERY-BLIND.** It is a function of the corpus seed and the path order. Nothing
|
|
1958
1958
|
* here reads the probe list, so a target's history is whatever its position in the corpus earns it.
|
|
1959
|
-
* A spread that
|
|
1959
|
+
* A spread that favored targets would make the gate pass by construction.
|
|
1960
1960
|
*
|
|
1961
1961
|
* The distribution is a long tail, `1 / (floor + jitter)`, because that is the shape retrieval traffic
|
|
1962
1962
|
* has: a handful of memories are read constantly and most are read once. A uniform count would make
|
|
@@ -2928,11 +2928,15 @@ const articleOf = (document) => {
|
|
|
2928
2928
|
* 24.4%. Both numbers are recorded because the measured one is the evidence and the deployed one
|
|
2929
2929
|
* is the decision.
|
|
2930
2930
|
*
|
|
2931
|
-
* DETERMINISM. highlight.js is pinned EXACTLY (`11.11.
|
|
2931
|
+
* DETERMINISM. highlight.js is pinned EXACTLY (`11.11.2`, no caret) in this package's
|
|
2932
2932
|
* `package.json`, because relevance scores are grammar-dependent: a version bump silently moves
|
|
2933
2933
|
* every confidence, and therefore which fences get stamped. The contract is "same input + same
|
|
2934
2934
|
* pinned version → same stamp". A bump is a deliberate decision that RE-RUNS the eval and
|
|
2935
|
-
* re-derives the threshold, not a routine dependency refresh.
|
|
2935
|
+
* re-derives the threshold, not a routine dependency refresh. Measured against 11.12.0 on
|
|
2936
|
+
* 2026-08-18, which is the size of "silently": `slice:example-service/mise.toml@42+9` fell 0.5406
|
|
2937
|
+
* to 0.1993 and stopped stamping `toml`, and one python row stopped stamping — coverage lost with
|
|
2938
|
+
* no evidence about precision, because the 332-snippet corpus that measured it lives in
|
|
2939
|
+
* `memhtml-evals`, not here. `.github/dependabot.yml` holds minor and major back for that reason.
|
|
2936
2940
|
*
|
|
2937
2941
|
* WRITE TIME ONLY. Detection runs on the write path and the result is stamped into the file, which
|
|
2938
2942
|
* is the system of record. Index rebuild reads `data-lang` back (`parse.ts`) and never re-detects,
|
|
@@ -4299,7 +4303,7 @@ const text = (result) => result.stdout.toString("utf8");
|
|
|
4299
4303
|
/**
|
|
4300
4304
|
* The service against a repository root. Exported rather than only wrapped in a layer, because every
|
|
4301
4305
|
* test in this package drives the real git binary against a temp-dir repo. A fake git
|
|
4302
|
-
* verifies the shape of these calls and not git's own
|
|
4306
|
+
* verifies the shape of these calls and not git's own behavior, and it is git's behavior
|
|
4303
4307
|
* (rename detection, index staging, merge conflict stages) that this package exists to use.
|
|
4304
4308
|
*/
|
|
4305
4309
|
const makeGit = (root) => ({
|
|
@@ -4657,7 +4661,7 @@ const subjectFor = (pending) => pending.length === 1 && pending[0] !== void 0 ?
|
|
|
4657
4661
|
const hasProvenance = (entry) => Object.keys(provenanceTrailers(entry.input)).length > 0;
|
|
4658
4662
|
/**
|
|
4659
4663
|
* The store over a git service. Exported so tests build it against a temp-dir repo with the
|
|
4660
|
-
* real git binary. This package's job IS git's
|
|
4664
|
+
* real git binary. This package's job IS git's behavior, so a fake git would verify only that
|
|
4661
4665
|
* the right strings were assembled and would miss every state transition that matters.
|
|
4662
4666
|
*/
|
|
4663
4667
|
const makeStore = (git, hooks = {}) => {
|
|
@@ -5995,7 +5999,7 @@ const IndexGit = Context.Service("memhtml/IndexGit");
|
|
|
5995
5999
|
* `onExcessProperty: "error"` means a column added to the SELECT without being added here is a
|
|
5996
6000
|
* decode failure, not a silently ignored field. Probed 2026-08-12 on node 24.19.0: `node:sqlite`
|
|
5997
6001
|
* hands back null-prototype records and `Schema.decodeUnknownEffect` reads them correctly, so the
|
|
5998
|
-
* driver's row objects need no
|
|
6002
|
+
* driver's row objects need no normalization at this seam.
|
|
5999
6003
|
*/
|
|
6000
6004
|
/**
|
|
6001
6005
|
* Every column of `index_state`, in the order `0007_watermark.sql` declares them.
|
|
@@ -7260,7 +7264,7 @@ const assembleScope = (scope = {}) => {
|
|
|
7260
7264
|
const types = (scope.memoryTypes ?? []).filter((type) => MEMORY_TYPES.includes(type));
|
|
7261
7265
|
if (types.length > 0)
|
|
7262
7266
|
/**
|
|
7263
|
-
* A caller-named type list is
|
|
7267
|
+
* A caller-named type list is honored VERBATIM, `task` included. Filtering `task` back out of
|
|
7264
7268
|
* an explicit list would make the opt-in unreachable, and there would then be no way to search
|
|
7265
7269
|
* tasks at all. The exclusion is a default and not a firewall. (The firewalls in this system are
|
|
7266
7270
|
* `edge_class` and the trace tables, and both reject a write rather than defaulting.)
|
|
@@ -7856,7 +7860,7 @@ const modelFailure = (modelId, cause) => ModelUnavailable.make({
|
|
|
7856
7860
|
* One InvokeModel round trip: send the body, decode the JSON payload. Both the transport
|
|
7857
7861
|
* rejection and an unparseable payload land on `ModelUnavailable`, because neither one
|
|
7858
7862
|
* says anything about the model's answer. They say only that no answer arrived. Reading
|
|
7859
|
-
* the answer, and judging whether it
|
|
7863
|
+
* the answer, and judging whether it honors its contract, is the caller's job.
|
|
7860
7864
|
*/
|
|
7861
7865
|
const invokeJson = (client, modelId, body) => Effect.gen(function* () {
|
|
7862
7866
|
const response = yield* Effect.tryPromise({
|
|
@@ -8924,7 +8928,7 @@ const ArcPlanEntry = Schema.Struct({
|
|
|
8924
8928
|
* slug would be a model-chosen file path.
|
|
8925
8929
|
*/
|
|
8926
8930
|
slug: Schema.String,
|
|
8927
|
-
/** A concise
|
|
8931
|
+
/** A concise behavioral-principal name, 3-8 words. */
|
|
8928
8932
|
title: Schema.String,
|
|
8929
8933
|
action: ArcAction,
|
|
8930
8934
|
/** One or two sentences naming what changed or emerged. */
|
|
@@ -8969,34 +8973,34 @@ memory, so when the two claims COULD both be true — different scope, different
|
|
|
8969
8973
|
aspect — answer neutral, not contradicts. Rate your confidence honestly and name the specific
|
|
8970
8974
|
conflicting or compatible claims in the rationale.`;
|
|
8971
8975
|
/** The arc-triage system prompt: plan only, no content. */
|
|
8972
|
-
const ARC_TRIAGE_SYSTEM = `You triage
|
|
8976
|
+
const ARC_TRIAGE_SYSTEM = `You triage behavioral arcs for an AI agent's long-term memory system. This is the planning pass:
|
|
8973
8977
|
a second pass writes each arc's content, so your output is only the plan.
|
|
8974
8978
|
|
|
8975
8979
|
- Assign every existing arc an action of update or skip. An arc omitted from the plan stays stale.
|
|
8976
|
-
- Propose create only when a genuinely new
|
|
8980
|
+
- Propose create only when a genuinely new behavioral pattern emerges that no existing arc covers.
|
|
8977
8981
|
- Propose update only when the evidence materially changes or reinforces the arc. Each update costs
|
|
8978
8982
|
a model call, so skip trivial or redundant evidence.
|
|
8979
8983
|
- Keep evidenceKeys to the strongest 1-5 supporting memories per arc.
|
|
8980
|
-
- Titles are concise
|
|
8984
|
+
- Titles are concise behavioral-principal names of 3-8 words.
|
|
8981
8985
|
- Rationale is one or two sentences naming what changed or emerged.
|
|
8982
8986
|
- Leave slug empty on a create.`;
|
|
8983
8987
|
/** The arc-execute system prompt: one arc's content. */
|
|
8984
|
-
const ARC_EXECUTE_SYSTEM = `You write one
|
|
8985
|
-
|
|
8988
|
+
const ARC_EXECUTE_SYSTEM = `You write one behavioral arc for an AI agent's long-term memory system. An arc is a self-contained
|
|
8989
|
+
behavioral principal — a statement of a pattern, preference, or principle the agent developed
|
|
8986
8990
|
through experience. Arcs are read back in future sessions with no transcript context, so the
|
|
8987
8991
|
content must stand alone.
|
|
8988
8992
|
|
|
8989
|
-
- claim is the ONE load-bearing sentence: the principle itself, stated as
|
|
8990
|
-
- paragraphs holds 2-12 sentences across one to four paragraphs.
|
|
8993
|
+
- claim is the ONE load-bearing sentence: the principle itself, stated as behavior to adopt.
|
|
8994
|
+
- paragraphs holds 2-12 sentences across one to four paragraphs. Behavioral principles fit at the
|
|
8991
8995
|
tight end; an operational playbook may span the wider range.
|
|
8992
|
-
- Use IF/THEN conditional phrasing for rules, framed positively around the
|
|
8996
|
+
- Use IF/THEN conditional phrasing for rules, framed positively around the behavior to adopt.
|
|
8993
8997
|
- When updating, incorporate both the existing content and the new evidence, preserving knowledge
|
|
8994
8998
|
that still holds.
|
|
8995
|
-
- Keep references like "the evidence" or "recent sessions" out of the text — name the
|
|
8999
|
+
- Keep references like "the evidence" or "recent sessions" out of the text — name the behavior.
|
|
8996
9000
|
- The content reads as a stable identity statement, not a changelog.`;
|
|
8997
9001
|
/** The compress-synthesis system prompt. */
|
|
8998
9002
|
const COMPRESS_SYSTEM = `You fold a group of related memories into ONE canonical memory for an AI agent's long-term memory
|
|
8999
|
-
system. The members are near-
|
|
9003
|
+
system. The members are near-neighbors in one community of the memory graph; the canonical replaces
|
|
9000
9004
|
them, and each member you list in absorbedKeys is archived once the canonical is written.
|
|
9001
9005
|
|
|
9002
9006
|
- claim is the ONE load-bearing sentence the group shares.
|
|
@@ -9012,13 +9016,13 @@ const dataBlock = (label, text) => wrapAsData(label, text);
|
|
|
9012
9016
|
* The stance judge's user turn for one pair. Both texts are wrapped; neither carries a path.
|
|
9013
9017
|
*
|
|
9014
9018
|
* The prompt names no path, no cosine, and no prior verdict, so the model cannot infer which answer
|
|
9015
|
-
* the caller is hoping for and cannot
|
|
9019
|
+
* the caller is hoping for and cannot recognize a pair it judged last night.
|
|
9016
9020
|
*/
|
|
9017
9021
|
const stancePrompt = (textA, textB) => `${dataBlock("memory_a", textA)}\n\n${dataBlock("memory_b", textB)}\n\nDo these two memories contradict each other? Give your verdict, your confidence, and a rationale naming the specific claims that conflict or why they are compatible.`;
|
|
9018
9022
|
/** The arc-triage user turn: the live arcs and the recent evidence, both wrapped. */
|
|
9019
|
-
const arcTriagePrompt = (arcsText, evidenceText) => `${dataBlock("current_arcs", arcsText)}\n\n${dataBlock("evidence", evidenceText)}\n\nProduce a triage plan. Assign update or skip to every existing arc, and add a create entry for any genuinely new
|
|
9023
|
+
const arcTriagePrompt = (arcsText, evidenceText) => `${dataBlock("current_arcs", arcsText)}\n\n${dataBlock("evidence", evidenceText)}\n\nProduce a triage plan. Assign update or skip to every existing arc, and add a create entry for any genuinely new behavioral pattern the existing arcs do not cover.`;
|
|
9020
9024
|
/** The arc-execute user turn for one arc. `current` is absent on a create. */
|
|
9021
|
-
const arcExecutePrompt = (input) => (input.current === void 0 ? `${dataBlock("new_arc_title", input.title)}\n\n` : `${dataBlock("existing_arc", input.current)}\n\n`) + `${dataBlock("evidence", input.evidenceText)}\n\n${dataBlock("triage_rationale", input.rationale)}\n\n` + (input.current === void 0 ? "Synthesize a new
|
|
9025
|
+
const arcExecutePrompt = (input) => (input.current === void 0 ? `${dataBlock("new_arc_title", input.title)}\n\n` : `${dataBlock("existing_arc", input.current)}\n\n`) + `${dataBlock("evidence", input.evidenceText)}\n\n${dataBlock("triage_rationale", input.rationale)}\n\n` + (input.current === void 0 ? "Synthesize a new behavioral principal from this evidence." : "Update the arc to incorporate the new evidence, preserving existing knowledge that holds.");
|
|
9022
9026
|
/** The compress user turn for one batch: every member's text, wrapped, under its offered key. */
|
|
9023
9027
|
const compressPrompt = (members) => `${members.map((member) => dataBlock(`member_${member.key}`, member.text)).join("\n\n")}\n\nFold these memories into one canonical memory. List in absorbedKeys exactly the members whose content the canonical carries forward.`;
|
|
9024
9028
|
/**
|
|
@@ -9077,11 +9081,11 @@ const activeCorpus = (db) => db.all(`SELECT path, memory_type, title, gist, body
|
|
|
9077
9081
|
word_count, created_at, updated_at, valid_until, reprieves
|
|
9078
9082
|
FROM files WHERE archived = 0 ORDER BY created_at ASC, path ASC`);
|
|
9079
9083
|
/**
|
|
9080
|
-
* Per-source top-`k` nearest
|
|
9084
|
+
* Per-source top-`k` nearest neighbors above a similarity floor, over first-chunk vectors.
|
|
9081
9085
|
*
|
|
9082
9086
|
* `ordinal = 0` collapses a file to its first chunk, not its best chunk. The format is one
|
|
9083
9087
|
* fact per file, so almost every file is a single chunk. Taking the first keeps the pair set
|
|
9084
|
-
* symmetric, which `min(distance)` over all chunks would not. An asymmetric
|
|
9088
|
+
* symmetric, which `min(distance)` over all chunks would not. An asymmetric neighborhood
|
|
9085
9089
|
* would make `(a, b)` a candidate while `(b, a)` is not, so which of two files was read first
|
|
9086
9090
|
* would decide whether they merge.
|
|
9087
9091
|
*
|
|
@@ -9090,7 +9094,7 @@ const activeCorpus = (db) => db.all(`SELECT path, memory_type, title, gist, body
|
|
|
9090
9094
|
* SQL function over two `Uint8Array` arguments (`packages/index/src/database.ts`) and not a driver
|
|
9091
9095
|
* builtin with a fixed calling shape.
|
|
9092
9096
|
*/
|
|
9093
|
-
const
|
|
9097
|
+
const neighborPairs = (db, options) => {
|
|
9094
9098
|
const excluded = options.excludeTypes ?? [];
|
|
9095
9099
|
const typeFilter = excluded.length === 0 ? "" : ` AND f.memory_type NOT IN (${excluded.map(() => "?").join(", ")})`;
|
|
9096
9100
|
return db.all(`WITH vecs AS (
|
|
@@ -9551,7 +9555,7 @@ const runRetentionPass = (db, at) => Effect.gen(function* () {
|
|
|
9551
9555
|
* `update`/`create` entries cost a second call.
|
|
9552
9556
|
*
|
|
9553
9557
|
* **One commit per arc, not one for the phase.** An arc is a standalone assertion about the agent's
|
|
9554
|
-
* own
|
|
9558
|
+
* own behavior, and a reviewer reads it as one thing; a commit carrying four unrelated arcs is a
|
|
9555
9559
|
* commit nobody reviews. It also means a model failure on the third arc leaves the first two
|
|
9556
9560
|
* committed, so the per-item isolation reaches the git history and not only the counters.
|
|
9557
9561
|
*
|
|
@@ -9996,7 +10000,7 @@ const confidenceDecay = (env) => Effect.gen(function* () {
|
|
|
9996
10000
|
*/
|
|
9997
10001
|
/** The moderate similarity floor a pair must clear to be worth a model call. */
|
|
9998
10002
|
const CONFLICT_COSINE_FLOOR = .8;
|
|
9999
|
-
/** Nearest same-entity
|
|
10003
|
+
/** Nearest same-entity neighbors considered per source. */
|
|
10000
10004
|
const CONFLICT_PER_SOURCE_K = 5;
|
|
10001
10005
|
/** Pairs judged per cycle. The model-cost guard. */
|
|
10002
10006
|
const CONFLICT_CANDIDATE_LIMIT = 200;
|
|
@@ -10139,7 +10143,7 @@ const dedupMerge = (env) => Effect.gen(function* () {
|
|
|
10139
10143
|
* The `files_content_hash_active` index carves tasks out for the same reason, so structural and
|
|
10140
10144
|
* semantic dedup agree about them.
|
|
10141
10145
|
*/
|
|
10142
|
-
const pairs = yield*
|
|
10146
|
+
const pairs = yield* neighborPairs(env.deps.db, {
|
|
10143
10147
|
floor: NEAR_DUPLICATE_THRESHOLD,
|
|
10144
10148
|
perSourceK: 5,
|
|
10145
10149
|
limit: 100 * 4,
|
|
@@ -10710,7 +10714,7 @@ const preflight = (env) => Effect.gen(function* () {
|
|
|
10710
10714
|
*/
|
|
10711
10715
|
/** The similarity floor a pair must clear to become a mined `relates_to`. */
|
|
10712
10716
|
const MINING_COSINE_FLOOR = .85;
|
|
10713
|
-
/** Nearest
|
|
10717
|
+
/** Nearest neighbors considered per source file. */
|
|
10714
10718
|
const MINING_PER_SOURCE_K = 5;
|
|
10715
10719
|
/** Pairs mined per cycle. The cost guard on a corpus whose pair space is quadratic. */
|
|
10716
10720
|
const MINING_SAMPLE_LIMIT = 2e3;
|
|
@@ -10722,7 +10726,7 @@ const relationshipMining = (env) => Effect.gen(function* () {
|
|
|
10722
10726
|
* count. The `edges` CHECK cannot refuse it, because `relates_to` under `memory` is a
|
|
10723
10727
|
* well-formed edge whatever files sit at its ends.
|
|
10724
10728
|
*/
|
|
10725
|
-
const pairs = yield*
|
|
10729
|
+
const pairs = yield* neighborPairs(env.deps.db, {
|
|
10726
10730
|
floor: MINING_COSINE_FLOOR,
|
|
10727
10731
|
perSourceK: 5,
|
|
10728
10732
|
limit: MINING_SAMPLE_LIMIT,
|
|
@@ -10878,7 +10882,7 @@ const headOf = (env) => env.deps.git.revParseHead().pipe(Effect.map((sha) => sha
|
|
|
10878
10882
|
* and re-assert the fact deliberately.
|
|
10879
10883
|
*
|
|
10880
10884
|
* **Arcs are exempt.** An arc is system-written and carries no meaningful TTL; expiring one on age
|
|
10881
|
-
* would delete the agent's own
|
|
10885
|
+
* would delete the agent's own behavioral identity on a schedule.
|
|
10882
10886
|
*/
|
|
10883
10887
|
const reprieve = (env) => Effect.gen(function* () {
|
|
10884
10888
|
const expired = (yield* runRetentionPass(env.deps.db, env.at)).scored.filter((entry) => {
|
|
@@ -11455,7 +11459,7 @@ const traceConsolidation = (env) => Effect.gen(function* () {
|
|
|
11455
11459
|
skipped,
|
|
11456
11460
|
conflicts: conflicted
|
|
11457
11461
|
};
|
|
11458
|
-
const commitSha = yield* commitPhase(env, "trace-consolidation", `${conflict === void 0 ? "
|
|
11462
|
+
const commitSha = yield* commitPhase(env, "trace-consolidation", `${conflict === void 0 ? "distill" : "distill (frame conflict)"} ${title}`, counts, commitContextFor(candidate, conflict));
|
|
11459
11463
|
if (commitSha !== null) lastCommit = commitSha;
|
|
11460
11464
|
written += 1;
|
|
11461
11465
|
}
|
|
@@ -12843,4 +12847,4 @@ const latest = (left, right) => left === null ? right : right === null ? left :
|
|
|
12843
12847
|
|
|
12844
12848
|
//#endregion
|
|
12845
12849
|
export { STATE_SIDECAR_PATH as $, makeIndexRecorder as A, makeGitPort as B, ModelClientLive as C, EMBED_DIM as D, EmbeddingsLive as E, reinforce as F, STATE_MIGRATIONS_DIR as G, DatabaseService as H, Indexer as I, expandRoot as J, STATE_SCHEMA as K, makeIndexer as L, readWatermark as M, Retrieval as N, EMBED_WATERMARK as O, makeRetrieval as P, STATE_DB_PATH as Q, readIndexState as R, ModelClient as S, Embeddings as T, makeDatabase as U, sanitizeFtsQuery as V, MIGRATIONS_DIR as W, INDEX_DB_PATH as X, makeStore as Y, SLEEP_REPORTS_DIR as Z, unlink as _, parseSidecar as a, commitSubject as at, discriminationGate as b, generateArtifacts as c, isValidDatetime as ct, danglingEdges as d, REINFORCE_SIGNALS as dt, attemptIo as et, publishRows as f, frameKeyOf as ft, meta as g, link as h, makeSleep as i, makeGit as it, persistScanned as j, IndexRecorder as k, accessRows as l, closesFence as lt, hrefFor as m, scanTraceRoot as n, readFileOrNull as nt, renderSidecar as o, checkMemory as ot, applyHeadEdits as p, Store as q, Sleep as r, Git as rt, archivedFormOf as s, setMeta as st, mergeTailExtract as t, initRepo as tt, allPaths as u, fenceOpeningOf as ut, SLEEP_PHASES as v, wrapAsData as w, runDiscrimination as x, isSleepPhase as y, IndexGit as z };
|
|
12846
|
-
//# sourceMappingURL=dist-
|
|
12850
|
+
//# sourceMappingURL=dist-dfrcDFad.mjs.map
|