hippo-memory 1.62.0 → 1.63.0
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 +9 -0
- package/dist/agent-memories/apply.d.ts +2 -0
- package/dist/agent-memories/apply.js +23 -1
- package/dist/agent-memories/claude-code.d.ts +2 -1
- package/dist/agent-memories/claude-code.js +4 -4
- package/dist/agent-memories/report.d.ts +1 -0
- package/dist/agent-memories/report.js +2 -2
- package/dist/agent-memories/sync.js +37 -23
- package/dist/ambient-store.d.ts +4 -4
- package/dist/ambient-store.js +4 -3
- package/dist/api/assemble.d.ts +7 -10
- package/dist/api/assemble.js +7 -12
- package/dist/api/audit.d.ts +2 -2
- package/dist/api/audit.js +2 -2
- package/dist/api/auth.d.ts +6 -6
- package/dist/api/auth.js +5 -7
- package/dist/api/context-select.d.ts +4 -3
- package/dist/api/context-select.js +9 -11
- package/dist/api/context-types.d.ts +12 -17
- package/dist/api/context.d.ts +3 -2
- package/dist/api/context.js +20 -20
- package/dist/api/dormant.js +1 -1
- package/dist/api/drill-down.d.ts +4 -4
- package/dist/api/drill-down.js +22 -10
- package/dist/api/outcome.d.ts +8 -13
- package/dist/api/outcome.js +13 -17
- package/dist/api/promote.d.ts +5 -8
- package/dist/api/quarantine.js +3 -2
- package/dist/api/recall-types.d.ts +43 -55
- package/dist/api/recall.d.ts +3 -3
- package/dist/api/recall.js +7 -18
- package/dist/api/remember.d.ts +2 -2
- package/dist/api/sleep.d.ts +7 -35
- package/dist/api/sleep.js +3 -2
- package/dist/api/tokens.d.ts +2 -2
- package/dist/api/tokens.js +2 -2
- package/dist/api/types.d.ts +6 -10
- package/dist/api/types.js +2 -4
- package/dist/audit-prune.d.ts +4 -6
- package/dist/audit-prune.js +3 -5
- package/dist/audit.js +11 -33
- package/dist/auth.d.ts +8 -9
- package/dist/auth.js +5 -7
- package/dist/autolearn.d.ts +1 -1
- package/dist/autolearn.js +1 -1
- package/dist/availability.js +3 -5
- package/dist/capture/command.d.ts +5 -4
- package/dist/capture/command.js +8 -22
- package/dist/capture/compact.d.ts +1 -1
- package/dist/capture/compact.js +9 -13
- package/dist/capture/extract.js +37 -115
- package/dist/capture-error.d.ts +1 -1
- package/dist/capture-error.js +1 -1
- package/dist/churn-git.d.ts +1 -1
- package/dist/churn-git.js +1 -1
- package/dist/cli/audit.js +3 -4
- package/dist/cli/auth.js +3 -6
- package/dist/cli/curate.d.ts +1 -1
- package/dist/cli/curate.js +8 -24
- package/dist/cli/dag.js +5 -9
- package/dist/cli/decisions.js +10 -21
- package/dist/cli/explain.js +2 -1
- package/dist/cli/goals.js +1 -1
- package/dist/cli/init.js +1 -1
- package/dist/cli/playbooks.js +4 -9
- package/dist/cli/projects.js +3 -1
- package/dist/cli/recall.js +2 -1
- package/dist/cli/remember.js +6 -18
- package/dist/cli/session-hooks.js +21 -40
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.js +2 -6
- package/dist/cli/shared.js +3 -3
- package/dist/cli/slack.js +1 -1
- package/dist/cli/sleep.js +27 -1
- package/dist/cli/status.d.ts +4 -4
- package/dist/cli/status.js +7 -12
- package/dist/cli/transfer.js +8 -13
- package/dist/cli/usage.js +9 -6
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +4 -9
- package/dist/compaction-record.d.ts +2 -0
- package/dist/compaction-record.js +89 -68
- package/dist/compare.d.ts +11 -16
- package/dist/compare.js +11 -16
- package/dist/config.d.ts +19 -18
- package/dist/config.js +90 -67
- package/dist/connectors/github/backfill.d.ts +2 -2
- package/dist/connectors/github/backfill.js +8 -15
- package/dist/connectors/github/cli-impl.js +3 -8
- package/dist/connectors/github/deletion.d.ts +5 -12
- package/dist/connectors/github/deletion.js +5 -12
- package/dist/connectors/github/dlq.d.ts +6 -9
- package/dist/connectors/github/dlq.js +2 -3
- package/dist/connectors/github/ingest.d.ts +5 -7
- package/dist/connectors/github/ingest.js +8 -12
- package/dist/connectors/github/octokit-client.d.ts +3 -5
- package/dist/connectors/github/octokit-client.js +5 -6
- package/dist/connectors/github/signature.d.ts +9 -39
- package/dist/connectors/github/signature.js +9 -39
- package/dist/connectors/github/tenant-routing.d.ts +1 -1
- package/dist/connectors/github/tenant-routing.js +1 -1
- package/dist/connectors/github/transform.js +2 -2
- package/dist/connectors/github/types.d.ts +2 -10
- package/dist/connectors/github/types.js +1 -3
- package/dist/connectors/slack/deletion.d.ts +3 -8
- package/dist/connectors/slack/deletion.js +3 -8
- package/dist/connectors/slack/dlq.d.ts +1 -1
- package/dist/connectors/slack/ingest.d.ts +1 -1
- package/dist/connectors/slack/ingest.js +7 -16
- package/dist/connectors/slack/signature.d.ts +1 -1
- package/dist/connectors/slack/tenant-routing.d.ts +3 -5
- package/dist/connectors/slack/tenant-routing.js +3 -5
- package/dist/connectors/slack/transform.d.ts +5 -6
- package/dist/connectors/slack/transform.js +5 -6
- package/dist/connectors/slack/types.d.ts +2 -6
- package/dist/connectors/slack/types.js +1 -3
- package/dist/connectors/slack/web-client.js +10 -3
- package/dist/connectors/slack/workspaces.d.ts +3 -5
- package/dist/connectors/slack/workspaces.js +3 -5
- package/dist/consolidate/conflicts.js +3 -14
- package/dist/consolidate/decay.js +9 -29
- package/dist/consolidate/llm-passes.js +4 -5
- package/dist/consolidate/merge.js +8 -23
- package/dist/consolidate/run.d.ts +1 -8
- package/dist/consolidate/run.js +3 -25
- package/dist/consolidate/sleep.js +5 -17
- package/dist/consolidate/traces.js +9 -21
- package/dist/customer-notes.d.ts +5 -7
- package/dist/customer-notes.js +6 -9
- package/dist/dag.d.ts +10 -21
- package/dist/dag.js +23 -73
- package/dist/db/continuity.js +2 -2
- package/dist/db/migrations/v14.js +1 -1
- package/dist/db/migrations/v15.js +1 -2
- package/dist/db/migrations/v16.js +3 -4
- package/dist/db/migrations/v17.js +2 -3
- package/dist/db/migrations/v19.js +1 -1
- package/dist/db/migrations/v20.js +1 -1
- package/dist/db/migrations/v21.js +2 -6
- package/dist/db/migrations/v22.js +2 -4
- package/dist/db/migrations/v23.js +1 -1
- package/dist/db/migrations/v24.js +4 -6
- package/dist/db/migrations/v25.js +2 -3
- package/dist/db/migrations/v26.js +3 -3
- package/dist/db/migrations/v27.js +2 -10
- package/dist/db/migrations/v28.js +5 -8
- package/dist/db/migrations/v29.js +3 -4
- package/dist/db/migrations/v30.js +2 -2
- package/dist/db/migrations/v31.js +1 -1
- package/dist/db/migrations/v32.js +1 -1
- package/dist/db/migrations/v33.js +3 -3
- package/dist/db/migrations/v34.js +1 -1
- package/dist/db/migrations/v35.js +3 -4
- package/dist/db/migrations/v36.js +3 -4
- package/dist/db/migrations/v37.js +5 -5
- package/dist/db/migrations/v38.js +7 -8
- package/dist/db/migrations/v39.js +1 -1
- package/dist/db/migrations/v40.js +4 -16
- package/dist/db/migrations/v41.js +3 -4
- package/dist/db/migrations/v42.js +3 -4
- package/dist/db/migrations/v45.js +1 -1
- package/dist/db/migrations/v46.js +1 -1
- package/dist/db/migrations/v47.js +1 -1
- package/dist/db/migrations/v48.js +1 -1
- package/dist/decisions.d.ts +2 -2
- package/dist/decisions.js +6 -6
- package/dist/dedupe.js +86 -61
- package/dist/delivery-recorder.js +154 -135
- package/dist/doctor.js +119 -104
- package/dist/dormant.js +1 -4
- package/dist/embedding-provider.d.ts +4 -8
- package/dist/embedding-provider.js +4 -8
- package/dist/embeddings.js +55 -47
- package/dist/env.d.ts +1 -1
- package/dist/env.js +12 -12
- package/dist/escape.d.ts +5 -0
- package/dist/escape.js +10 -0
- package/dist/eval-stats.d.ts +1 -2
- package/dist/eval-stats.js +1 -2
- package/dist/eval-suite.js +27 -21
- package/dist/extract.js +4 -9
- package/dist/failure-log.d.ts +3 -3
- package/dist/failure-log.js +1 -1
- package/dist/forward-claim-detector.d.ts +2 -4
- package/dist/forward-claim-detector.js +6 -11
- package/dist/goals.d.ts +3 -3
- package/dist/goals.js +5 -6
- package/dist/graph/read.d.ts +2 -2
- package/dist/graph/read.js +5 -6
- package/dist/graph/types.d.ts +8 -8
- package/dist/graph/write.d.ts +7 -14
- package/dist/graph/write.js +16 -23
- package/dist/graph-extract.d.ts +7 -8
- package/dist/graph-extract.js +62 -72
- package/dist/graph-recall.d.ts +2 -2
- package/dist/graph-recall.js +55 -49
- package/dist/graph-stream.d.ts +5 -6
- package/dist/graph-stream.js +66 -57
- package/dist/graph-view.d.ts +2 -2
- package/dist/graph-view.js +7 -7
- package/dist/half-life-migration.d.ts +1 -2
- package/dist/half-life-migration.js +2 -3
- package/dist/hooks/codex-session.js +1 -1
- package/dist/hooks/codex-wrapper.d.ts +1 -1
- package/dist/hooks/codex-wrapper.js +3 -2
- package/dist/hooks/json-hooks.d.ts +2 -2
- package/dist/hooks/json-hooks.js +5 -4
- package/dist/hooks/opencode.d.ts +1 -1
- package/dist/hooks/opencode.js +5 -4
- package/dist/hooks/shared.d.ts +3 -7
- package/dist/hooks/shared.js +1 -8
- package/dist/http-util.d.ts +2 -3
- package/dist/http-util.js +3 -0
- package/dist/importers/core.d.ts +2 -9
- package/dist/importers/core.js +15 -30
- package/dist/importers/sources.js +2 -1
- package/dist/importers/vault.js +2 -20
- package/dist/incidents.d.ts +1 -1
- package/dist/incidents.js +1 -1
- package/dist/instruction-detect.d.ts +1 -1
- package/dist/instruction-detect.js +1 -1
- package/dist/invalidation.d.ts +3 -0
- package/dist/invalidation.js +160 -114
- package/dist/json.d.ts +5 -0
- package/dist/json.js +4 -0
- package/dist/judgment.js +1 -2
- package/dist/local-embedding.js +1 -1
- package/dist/mcp/admin-tools.js +7 -17
- package/dist/mcp/format.js +1 -1
- package/dist/mcp/framing.js +3 -6
- package/dist/mcp/protocol.d.ts +2 -5
- package/dist/mcp/protocol.js +1 -3
- package/dist/mcp/recall-tools.js +12 -15
- package/dist/mcp/request.js +4 -3
- package/dist/mcp/session-state.js +2 -3
- package/dist/mcp/stdio.js +2 -1
- package/dist/mcp/tools.js +9 -6
- package/dist/memory-value-weights.d.ts +5 -8
- package/dist/memory-value-weights.js +5 -8
- package/dist/memory-value.d.ts +13 -13
- package/dist/memory-value.js +26 -37
- package/dist/memory.d.ts +20 -22
- package/dist/memory.js +24 -48
- package/dist/multihop.d.ts +1 -1
- package/dist/multihop.js +3 -2
- package/dist/owner-validation.d.ts +4 -5
- package/dist/owner-validation.js +4 -5
- package/dist/physics.d.ts +4 -4
- package/dist/physics.js +7 -9
- package/dist/policies.d.ts +9 -10
- package/dist/policies.js +12 -14
- package/dist/postinstall.js +3 -6
- package/dist/predictions/planning-fallacy.d.ts +9 -14
- package/dist/predictions/planning-fallacy.js +10 -16
- package/dist/predictions/store.d.ts +15 -23
- package/dist/predictions/store.js +36 -33
- package/dist/processes.d.ts +2 -7
- package/dist/processes.js +3 -3
- package/dist/project-briefs.d.ts +2 -3
- package/dist/project-briefs.js +9 -13
- package/dist/project-identity.d.ts +22 -9
- package/dist/project-identity.js +47 -12
- package/dist/project-merge.d.ts +17 -2
- package/dist/project-merge.js +109 -27
- package/dist/project-remote.d.ts +12 -0
- package/dist/project-remote.js +138 -0
- package/dist/prompt-recall.js +1 -2
- package/dist/rate-limit.d.ts +1 -1
- package/dist/rate-limit.js +1 -1
- package/dist/raw-archive.d.ts +9 -0
- package/dist/raw-archive.js +70 -53
- package/dist/recall-history.d.ts +19 -20
- package/dist/recall-history.js +24 -42
- package/dist/recall-pipeline.js +4 -28
- package/dist/recall-scope.d.ts +7 -8
- package/dist/recall-scope.js +7 -8
- package/dist/recall-trace.d.ts +5 -9
- package/dist/recall-trace.js +6 -10
- package/dist/refine-llm.d.ts +1 -1
- package/dist/refine-llm.js +2 -2
- package/dist/reject-flow.d.ts +3 -4
- package/dist/reject-flow.js +122 -117
- package/dist/rejection.d.ts +5 -6
- package/dist/rejection.js +7 -15
- package/dist/rerankers/clef.d.ts +1 -1
- package/dist/rerankers/jev.d.ts +1 -2
- package/dist/rerankers/jev.js +4 -5
- package/dist/rerankers/llm.d.ts +1 -2
- package/dist/rerankers/llm.js +1 -2
- package/dist/rerankers/types.d.ts +1 -2
- package/dist/rrf.d.ts +2 -2
- package/dist/rrf.js +2 -2
- package/dist/search/bm25-search.d.ts +1 -1
- package/dist/search/bm25-search.js +2 -1
- package/dist/search/boosts.js +2 -1
- package/dist/search/hybrid.d.ts +1 -1
- package/dist/search/hybrid.js +2 -1
- package/dist/search/physics-search.d.ts +1 -1
- package/dist/search/physics-search.js +2 -1
- package/dist/search/types.d.ts +2 -0
- package/dist/search/types.js +3 -1
- package/dist/secret-detect.d.ts +4 -5
- package/dist/secret-detect.js +6 -10
- package/dist/server/auth.js +5 -5
- package/dist/server/client-ip.js +1 -1
- package/dist/server/cursor.js +2 -1
- package/dist/server/mcp-http.js +4 -4
- package/dist/server/request.d.ts +3 -6
- package/dist/server/request.js +6 -7
- package/dist/server/routes/admin.js +5 -4
- package/dist/server/routes/customer-notes.js +6 -5
- package/dist/server/routes/decisions.js +4 -3
- package/dist/server/routes/incidents.js +7 -5
- package/dist/server/routes/memories.js +7 -7
- package/dist/server/routes/policies.js +3 -2
- package/dist/server/routes/predictions.js +12 -15
- package/dist/server/routes/processes.js +3 -2
- package/dist/server/routes/project-briefs.js +8 -7
- package/dist/server/routes/recall.js +95 -93
- package/dist/server/routes/skills.js +6 -5
- package/dist/server/types.d.ts +1 -1
- package/dist/server/validation.d.ts +1 -2
- package/dist/server/validation.js +7 -14
- package/dist/server-detect.js +72 -58
- package/dist/server.d.ts +2 -2
- package/dist/server.js +131 -117
- package/dist/shared.d.ts +17 -17
- package/dist/shared.js +93 -97
- package/dist/skills.d.ts +3 -3
- package/dist/skills.js +8 -8
- package/dist/store/audit-event.d.ts +2 -2
- package/dist/store/audit-event.js +1 -1
- package/dist/store/candidates.d.ts +2 -2
- package/dist/store/candidates.js +4 -3
- package/dist/store/conflicts.js +30 -22
- package/dist/store/delete-and-batch.d.ts +11 -14
- package/dist/store/delete-and-batch.js +40 -91
- package/dist/store/entry-reads.d.ts +17 -25
- package/dist/store/entry-reads.js +59 -40
- package/dist/store/entry-row.d.ts +6 -24
- package/dist/store/entry-row.js +6 -24
- package/dist/store/entry-writes.d.ts +6 -7
- package/dist/store/entry-writes.js +13 -11
- package/dist/store/handoffs.d.ts +1 -1
- package/dist/store/handoffs.js +7 -10
- package/dist/store/index-and-stats.d.ts +2 -6
- package/dist/store/index-and-stats.js +4 -10
- package/dist/store/mirrors.d.ts +6 -19
- package/dist/store/mirrors.js +14 -39
- package/dist/store/open.js +9 -31
- package/dist/store/rows.d.ts +5 -11
- package/dist/store/rows.js +6 -11
- package/dist/store/search-rows.d.ts +17 -34
- package/dist/store/search-rows.js +31 -59
- package/dist/store/sessions.d.ts +4 -5
- package/dist/store/sessions.js +5 -6
- package/dist/store/summaries.d.ts +13 -17
- package/dist/store/summaries.js +26 -70
- package/dist/support-bundle.js +4 -8
- package/dist/tenant.d.ts +1 -5
- package/dist/token-ledger.d.ts +1 -1
- package/dist/token-ledger.js +3 -5
- package/dist/trace.js +1 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/working-memory.d.ts +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/mcp/tools.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// Tool definitions and input schemas served by tools/list.
|
|
2
|
+
import { DEFAULT_RECALL_BUDGET } from '../search/types.js';
|
|
3
|
+
import { DEFAULT_ASSEMBLE_BUDGET } from '../api/assemble.js';
|
|
4
|
+
import { MAX_ID_LEN } from '../http-util.js';
|
|
2
5
|
// ── Tool definitions ──
|
|
3
|
-
// HTTP sets no budget cap; 25x the
|
|
4
|
-
const MAX_BUDGET_TOKENS =
|
|
6
|
+
// HTTP sets no budget cap; 25x the recall default leaves room for large-context clients while bounding one call's work.
|
|
7
|
+
const MAX_BUDGET_TOKENS = 25 * DEFAULT_RECALL_BUDGET;
|
|
5
8
|
// Same ceiling as the HTTP list routes' parseListLimit.
|
|
6
9
|
const MAX_LIST_LIMIT = 1000;
|
|
7
10
|
export const TOOLS = [
|
|
@@ -16,7 +19,7 @@ export const TOOLS = [
|
|
|
16
19
|
type: 'number',
|
|
17
20
|
minimum: 0,
|
|
18
21
|
maximum: MAX_BUDGET_TOKENS,
|
|
19
|
-
description: `Max tokens to return (default: config.defaultBudget,
|
|
22
|
+
description: `Max tokens to return (default: config.defaultBudget, ${DEFAULT_RECALL_BUDGET}; max ${MAX_BUDGET_TOKENS})`,
|
|
20
23
|
},
|
|
21
24
|
include_continuity: {
|
|
22
25
|
type: 'boolean',
|
|
@@ -44,8 +47,8 @@ export const TOOLS = [
|
|
|
44
47
|
},
|
|
45
48
|
session_id: {
|
|
46
49
|
type: 'string',
|
|
47
|
-
maxLength:
|
|
48
|
-
description:
|
|
50
|
+
maxLength: MAX_ID_LEN,
|
|
51
|
+
description: `Optional session id (v1.7.4). When set AND (tenant, session) has active goals, applies the dlPFC goal-stack boost to the ranked memories before formatting. Mirrors fresh_tail_session_id shape (${MAX_ID_LEN}-char cap).`,
|
|
49
52
|
},
|
|
50
53
|
},
|
|
51
54
|
required: ['query'],
|
|
@@ -65,7 +68,7 @@ export const TOOLS = [
|
|
|
65
68
|
type: 'number',
|
|
66
69
|
minimum: 0,
|
|
67
70
|
maximum: MAX_BUDGET_TOKENS,
|
|
68
|
-
description: `Token budget for the assembled context (default
|
|
71
|
+
description: `Token budget for the assembled context (default ${DEFAULT_ASSEMBLE_BUDGET}; max ${MAX_BUDGET_TOKENS}). Eviction kicks in over budget.`,
|
|
69
72
|
},
|
|
70
73
|
fresh_tail_count: {
|
|
71
74
|
type: 'number',
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Frozen learned memory-value weight vector.
|
|
3
3
|
*
|
|
4
|
-
* GENERATED FROM the
|
|
4
|
+
* GENERATED FROM the frozen artifact
|
|
5
5
|
* (benchmarks/memory-value/weights-learned.json +
|
|
6
6
|
* benchmarks/memory-value/weights-learned.meta.json). NEVER EDIT BY HAND —
|
|
7
7
|
* tests/memory-value-wiring.test.ts's weights-sync test asserts this constant
|
|
8
8
|
* equals the committed JSON artifact (value equality + digest match), so
|
|
9
9
|
* drift between the artifact and this file fails CI.
|
|
10
10
|
*
|
|
11
|
-
* CAVEAT
|
|
12
|
-
*
|
|
13
|
-
* usage-feature signs reflect E1's anti-oracle simulation, NOT real usage
|
|
14
|
-
* value. Never read this as production ranking advice — LC3 tests real
|
|
15
|
-
* usage value.
|
|
11
|
+
* CAVEAT: usage-feature signs reflect an anti-oracle simulation, NOT real usage
|
|
12
|
+
* value. Never read this as production ranking advice.
|
|
16
13
|
*/
|
|
17
|
-
/** The 8 live feature dims the
|
|
14
|
+
/** The 8 live feature dims the fitter optimized over (FIT_DIMS). */
|
|
18
15
|
export declare const MEMORY_VALUE_WEIGHTS: Readonly<Record<string, number>>;
|
|
19
16
|
/** sha256 of benchmarks/memory-value/weights-learned.json at freeze time
|
|
20
17
|
* (weights-learned.meta.json's `weightsFileSha256`). */
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Frozen learned memory-value weight vector.
|
|
3
3
|
*
|
|
4
|
-
* GENERATED FROM the
|
|
4
|
+
* GENERATED FROM the frozen artifact
|
|
5
5
|
* (benchmarks/memory-value/weights-learned.json +
|
|
6
6
|
* benchmarks/memory-value/weights-learned.meta.json). NEVER EDIT BY HAND —
|
|
7
7
|
* tests/memory-value-wiring.test.ts's weights-sync test asserts this constant
|
|
8
8
|
* equals the committed JSON artifact (value equality + digest match), so
|
|
9
9
|
* drift between the artifact and this file fails CI.
|
|
10
10
|
*
|
|
11
|
-
* CAVEAT
|
|
12
|
-
*
|
|
13
|
-
* usage-feature signs reflect E1's anti-oracle simulation, NOT real usage
|
|
14
|
-
* value. Never read this as production ranking advice — LC3 tests real
|
|
15
|
-
* usage value.
|
|
11
|
+
* CAVEAT: usage-feature signs reflect an anti-oracle simulation, NOT real usage
|
|
12
|
+
* value. Never read this as production ranking advice.
|
|
16
13
|
*/
|
|
17
|
-
/** The 8 live feature dims the
|
|
14
|
+
/** The 8 live feature dims the fitter optimized over (FIT_DIMS). */
|
|
18
15
|
export const MEMORY_VALUE_WEIGHTS = Object.freeze({
|
|
19
16
|
age_days: -0.3245577821391783,
|
|
20
17
|
half_life_days: 0.11410695580440973,
|
package/dist/memory-value.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* rescue-only veto
|
|
2
|
+
* Learned memory-value scorer, wired into the sleep decay pass as a
|
|
3
|
+
* rescue-only veto.
|
|
4
4
|
*
|
|
5
5
|
* computeMvFeatures mirrors benchmarks/memory-value/extract.mjs's
|
|
6
|
-
* computeFeatures for the 8 live dims the
|
|
6
|
+
* computeFeatures for the 8 live dims the fitter optimized over
|
|
7
7
|
* (FIT_DIMS) — the only dims MEMORY_VALUE_WEIGHTS carries a weight for.
|
|
8
8
|
* Any future edit to either side must keep them byte-equivalent; the parity
|
|
9
9
|
* test in tests/memory-value-wiring.test.ts enforces this.
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
* min-max normalization + weighted scorer (no additional orientation
|
|
13
13
|
* multiply — the frozen weights already encode sign/orientation).
|
|
14
14
|
*
|
|
15
|
-
* rescueSet implements
|
|
16
|
-
* rescued iff its learned score ranks in the top 30% (RESCUE_BUDGET, the
|
|
17
|
-
* keep-budget operating point) of its own tenant's non-pinned
|
|
18
|
-
*
|
|
15
|
+
* rescueSet implements rescue-only semantics: a condemned entry is
|
|
16
|
+
* rescued iff its learned score ranks in the top 30% (RESCUE_BUDGET, the
|
|
17
|
+
* measured keep-budget operating point) of its own tenant's non-pinned
|
|
18
|
+
* candidate set. Deletes(flag-on) subset Deletes(flag-off) by construction — this
|
|
19
19
|
* function can only ever shrink the condemned set, never grow it.
|
|
20
20
|
*/
|
|
21
21
|
import { type MemoryEntry } from './memory.js';
|
|
@@ -50,13 +50,13 @@ export declare function validateWeights(weights?: Readonly<Record<string, number
|
|
|
50
50
|
* Min-max normalize each of the 8 features over the given entry set
|
|
51
51
|
* (constant feature -> 0, matching evaluate.mjs), then score = dot(weights,
|
|
52
52
|
* normalized). The normalization context is exactly the entries passed in —
|
|
53
|
-
* callers control the bounded scope (
|
|
53
|
+
* callers control the bounded scope (per-tenant, non-pinned).
|
|
54
54
|
*
|
|
55
55
|
* `weights` defaults to the real frozen singleton; parameterized (like
|
|
56
56
|
* validateWeights) so callers/tests can score against an explicit vector
|
|
57
57
|
* without touching the module singleton.
|
|
58
58
|
*
|
|
59
|
-
*
|
|
59
|
+
* Non-finite features: Date.parse on a malformed `created`
|
|
60
60
|
* string yields NaN, and NaN would silently corrupt every OTHER entry's
|
|
61
61
|
* min-max in the same group. An entry with ANY non-finite computed feature
|
|
62
62
|
* is excluded from the normalization context entirely (its raw values never
|
|
@@ -74,13 +74,13 @@ export interface MvRankInfo {
|
|
|
74
74
|
score: number;
|
|
75
75
|
/** 1-based rank by score DESC within the tenant's non-pinned candidate set. */
|
|
76
76
|
rank: number;
|
|
77
|
-
/** Size of the tenant's non-pinned candidate set
|
|
77
|
+
/** Size of the tenant's non-pinned candidate set. */
|
|
78
78
|
totalNonPinned: number;
|
|
79
79
|
/** ceil(RESCUE_BUDGET * totalNonPinned) — the rescue cutoff; rank <= keepN rescues. */
|
|
80
80
|
keepN: number;
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
|
-
* Groups non-pinned entries by tenantId
|
|
83
|
+
* Groups non-pinned entries by tenantId, scores + ranks each tenant's
|
|
84
84
|
* group independently, and returns per-entry rank context for every
|
|
85
85
|
* non-pinned entry (not just condemned ones) — the shared basis for both
|
|
86
86
|
* rescueSet's rescue decision and consolidate.ts's audit-row rank context,
|
|
@@ -92,7 +92,7 @@ export interface MvRankInfo {
|
|
|
92
92
|
*/
|
|
93
93
|
export declare function rankNonPinnedByTenant(entries: MemoryEntry[], now: Date, weights?: Readonly<Record<string, number>>, digest?: string): Map<string, MvRankInfo>;
|
|
94
94
|
/**
|
|
95
|
-
*
|
|
95
|
+
* Rescue decision: a condemned entry is rescued iff it ranks in the top
|
|
96
96
|
* 30% of its tenant's non-pinned candidate set by learned score. Returns the
|
|
97
97
|
* subset of condemnedIds that are rescued — the caller filters commits
|
|
98
98
|
* (rescued -> survivors) and threads the same set into detectConflicts.
|
|
@@ -102,7 +102,7 @@ export declare function rankNonPinnedByTenant(entries: MemoryEntry[], now: Date,
|
|
|
102
102
|
* "flag on + a broken constant throws" is directly testable end-to-end
|
|
103
103
|
* through this function without mutating the frozen module singleton.
|
|
104
104
|
*
|
|
105
|
-
* `precomputedRanks
|
|
105
|
+
* `precomputedRanks`: when the caller has already
|
|
106
106
|
* computed the per-tenant ranking (e.g. consolidate.ts needs it separately
|
|
107
107
|
* for detail/audit rank context), pass it here to skip the internal
|
|
108
108
|
* rankNonPinnedByTenant call — the whole-store ranking pass then runs
|
package/dist/memory-value.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* rescue-only veto
|
|
2
|
+
* Learned memory-value scorer, wired into the sleep decay pass as a
|
|
3
|
+
* rescue-only veto.
|
|
4
4
|
*
|
|
5
5
|
* computeMvFeatures mirrors benchmarks/memory-value/extract.mjs's
|
|
6
|
-
* computeFeatures for the 8 live dims the
|
|
6
|
+
* computeFeatures for the 8 live dims the fitter optimized over
|
|
7
7
|
* (FIT_DIMS) — the only dims MEMORY_VALUE_WEIGHTS carries a weight for.
|
|
8
8
|
* Any future edit to either side must keep them byte-equivalent; the parity
|
|
9
9
|
* test in tests/memory-value-wiring.test.ts enforces this.
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
* min-max normalization + weighted scorer (no additional orientation
|
|
13
13
|
* multiply — the frozen weights already encode sign/orientation).
|
|
14
14
|
*
|
|
15
|
-
* rescueSet implements
|
|
16
|
-
* rescued iff its learned score ranks in the top 30% (RESCUE_BUDGET, the
|
|
17
|
-
* keep-budget operating point) of its own tenant's non-pinned
|
|
18
|
-
*
|
|
15
|
+
* rescueSet implements rescue-only semantics: a condemned entry is
|
|
16
|
+
* rescued iff its learned score ranks in the top 30% (RESCUE_BUDGET, the
|
|
17
|
+
* measured keep-budget operating point) of its own tenant's non-pinned
|
|
18
|
+
* candidate set. Deletes(flag-on) subset Deletes(flag-off) by construction — this
|
|
19
19
|
* function can only ever shrink the condemned set, never grow it.
|
|
20
20
|
*/
|
|
21
21
|
import { calculateStrength } from './memory.js';
|
|
@@ -32,13 +32,13 @@ export const MV_FEATURE_NAMES = [
|
|
|
32
32
|
'outcome_ratio',
|
|
33
33
|
'content_length',
|
|
34
34
|
];
|
|
35
|
-
/** The
|
|
36
|
-
* evidence)
|
|
35
|
+
/** The keep-budget operating point (the only point with measured
|
|
36
|
+
* evidence): a code constant tied to that evidence, not user-tunable. */
|
|
37
37
|
const RESCUE_BUDGET = 0.3;
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
39
|
+
* Small-tenant degeneracy: below this per-tenant non-pinned candidate-set
|
|
40
|
+
* size, a rank statistic is noise (the measured evidence says nothing about
|
|
41
|
+
* tiny scale), and the floor prevents immortal-entry
|
|
42
42
|
* convergence: keepN=ceil(0.3*N) guarantees >=1 rescue at N=1, so without a
|
|
43
43
|
* floor a condemned-only 1-entry tenant would be rescued every single sleep
|
|
44
44
|
* forever. A condemned-only tenant below the floor instead drains normally
|
|
@@ -108,13 +108,13 @@ export function validateWeights(weights = MEMORY_VALUE_WEIGHTS, digest = SOURCE_
|
|
|
108
108
|
* Min-max normalize each of the 8 features over the given entry set
|
|
109
109
|
* (constant feature -> 0, matching evaluate.mjs), then score = dot(weights,
|
|
110
110
|
* normalized). The normalization context is exactly the entries passed in —
|
|
111
|
-
* callers control the bounded scope (
|
|
111
|
+
* callers control the bounded scope (per-tenant, non-pinned).
|
|
112
112
|
*
|
|
113
113
|
* `weights` defaults to the real frozen singleton; parameterized (like
|
|
114
114
|
* validateWeights) so callers/tests can score against an explicit vector
|
|
115
115
|
* without touching the module singleton.
|
|
116
116
|
*
|
|
117
|
-
*
|
|
117
|
+
* Non-finite features: Date.parse on a malformed `created`
|
|
118
118
|
* string yields NaN, and NaN would silently corrupt every OTHER entry's
|
|
119
119
|
* min-max in the same group. An entry with ANY non-finite computed feature
|
|
120
120
|
* is excluded from the normalization context entirely (its raw values never
|
|
@@ -166,7 +166,7 @@ export function scoreEntries(entries, now, weights = MEMORY_VALUE_WEIGHTS) {
|
|
|
166
166
|
return scores;
|
|
167
167
|
}
|
|
168
168
|
/**
|
|
169
|
-
* Groups non-pinned entries by tenantId
|
|
169
|
+
* Groups non-pinned entries by tenantId, scores + ranks each tenant's
|
|
170
170
|
* group independently, and returns per-entry rank context for every
|
|
171
171
|
* non-pinned entry (not just condemned ones) — the shared basis for both
|
|
172
172
|
* rescueSet's rescue decision and consolidate.ts's audit-row rank context,
|
|
@@ -181,11 +181,9 @@ export function rankNonPinnedByTenant(entries, now, weights = MEMORY_VALUE_WEIGH
|
|
|
181
181
|
const byTenant = new Map();
|
|
182
182
|
for (const e of entries) {
|
|
183
183
|
if (e.pinned)
|
|
184
|
-
continue; //
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
// undefined at runtime, and grouping it under the literal key
|
|
188
|
-
// "undefined" would silently split it into its own singleton tenant.
|
|
184
|
+
continue; // pinned entries never compete for rescue (never condemned)
|
|
185
|
+
// Default an undefined tenantId as dag.ts:341 does: a raw/legacy row can carry one at runtime,
|
|
186
|
+
// and keying it "undefined" would split it into its own singleton tenant.
|
|
189
187
|
const tenantId = e.tenantId ?? 'default';
|
|
190
188
|
const list = byTenant.get(tenantId);
|
|
191
189
|
if (list)
|
|
@@ -196,19 +194,13 @@ export function rankNonPinnedByTenant(entries, now, weights = MEMORY_VALUE_WEIGH
|
|
|
196
194
|
const result = new Map();
|
|
197
195
|
for (const [tenantId, group] of byTenant) {
|
|
198
196
|
const scores = scoreEntries(group, now, weights);
|
|
199
|
-
// score DESC
|
|
200
|
-
//
|
|
201
|
-
// codebase (src/compare.ts). F2: `-Infinity - -Infinity` is NaN, not 0 —
|
|
202
|
-
// two non-finite-feature entries tied at -Infinity would otherwise fall
|
|
203
|
-
// through to `diff` (NaN), which Array.sort treats as "no preference"
|
|
204
|
-
// and leaves insertion-order-dependent. Route NaN through the same
|
|
205
|
-
// deterministic tie-break as an exact-zero diff.
|
|
197
|
+
// score DESC, then compareEntryIdentity, the shared tie-break of every score-primary sort (src/compare.ts).
|
|
198
|
+
// `-Infinity - -Infinity` is NaN, which Array.sort leaves insertion-order-dependent, so NaN ties too.
|
|
206
199
|
const sorted = [...group].sort((a, b) => {
|
|
207
200
|
const diff = scores.get(b.id) - scores.get(a.id);
|
|
208
201
|
return diff === 0 || Number.isNaN(diff) ? compareEntryIdentity(a, b) : diff;
|
|
209
202
|
});
|
|
210
|
-
//
|
|
211
|
-
// that constant's doc comment.
|
|
203
|
+
// Tenants smaller than MIN_RESCUE_GROUP never rescue (keepN 0); see that constant's doc comment.
|
|
212
204
|
const keepN = sorted.length < MIN_RESCUE_GROUP
|
|
213
205
|
? 0
|
|
214
206
|
: Math.min(sorted.length, Math.ceil(RESCUE_BUDGET * sorted.length));
|
|
@@ -225,7 +217,7 @@ export function rankNonPinnedByTenant(entries, now, weights = MEMORY_VALUE_WEIGH
|
|
|
225
217
|
return result;
|
|
226
218
|
}
|
|
227
219
|
/**
|
|
228
|
-
*
|
|
220
|
+
* Rescue decision: a condemned entry is rescued iff it ranks in the top
|
|
229
221
|
* 30% of its tenant's non-pinned candidate set by learned score. Returns the
|
|
230
222
|
* subset of condemnedIds that are rescued — the caller filters commits
|
|
231
223
|
* (rescued -> survivors) and threads the same set into detectConflicts.
|
|
@@ -235,7 +227,7 @@ export function rankNonPinnedByTenant(entries, now, weights = MEMORY_VALUE_WEIGH
|
|
|
235
227
|
* "flag on + a broken constant throws" is directly testable end-to-end
|
|
236
228
|
* through this function without mutating the frozen module singleton.
|
|
237
229
|
*
|
|
238
|
-
* `precomputedRanks
|
|
230
|
+
* `precomputedRanks`: when the caller has already
|
|
239
231
|
* computed the per-tenant ranking (e.g. consolidate.ts needs it separately
|
|
240
232
|
* for detail/audit rank context), pass it here to skip the internal
|
|
241
233
|
* rankNonPinnedByTenant call — the whole-store ranking pass then runs
|
|
@@ -243,16 +235,13 @@ export function rankNonPinnedByTenant(entries, now, weights = MEMORY_VALUE_WEIGH
|
|
|
243
235
|
* computes it internally as before — existing callers/tests are unaffected.
|
|
244
236
|
*/
|
|
245
237
|
export function rescueSet(entries, condemnedIds, now, weights = MEMORY_VALUE_WEIGHTS, digest = SOURCE_ARTIFACT_SHA256, precomputedRanks) {
|
|
246
|
-
validateWeights(weights, digest); // fail loud before any rescue computation
|
|
238
|
+
validateWeights(weights, digest); // fail loud before any rescue computation
|
|
247
239
|
const ranked = precomputedRanks ?? rankNonPinnedByTenant(entries, now, weights, digest);
|
|
248
240
|
const rescued = new Set();
|
|
249
241
|
for (const id of condemnedIds) {
|
|
250
242
|
const info = ranked.get(id);
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
// case where every entry in a tenant is non-finite-scored (a tie at
|
|
254
|
-
// -Infinity), rank position alone could otherwise place one inside
|
|
255
|
-
// keepN; this makes "never rescued" hold regardless.
|
|
243
|
+
// An explicit finite guard, not just -Infinity sorting last: when a whole tenant
|
|
244
|
+
// ties at -Infinity, rank alone could place one inside keepN.
|
|
256
245
|
if (info && info.rank <= info.keepN && Number.isFinite(info.score))
|
|
257
246
|
rescued.add(id);
|
|
258
247
|
}
|
package/dist/memory.d.ts
CHANGED
|
@@ -30,8 +30,8 @@ export type MemoryKind = 'raw' | 'distilled' | 'superseded' | 'archived';
|
|
|
30
30
|
*
|
|
31
31
|
* Byte-comparison sort (`<` / `>`) is chronological for any pair of
|
|
32
32
|
* canonical UTC ISO strings. ~50× faster than `localeCompare` with no
|
|
33
|
-
* semantic gain.
|
|
34
|
-
* import path admits non-canonical timestamps,
|
|
33
|
+
* semantic gain. `assemble` sorts by byte compare; if a future
|
|
34
|
+
* import path admits non-canonical timestamps, that sort and any
|
|
35
35
|
* downstream chronological reasoning will need a normalization pass.
|
|
36
36
|
*/
|
|
37
37
|
export interface MemoryEntry {
|
|
@@ -65,18 +65,18 @@ export interface MemoryEntry {
|
|
|
65
65
|
descendant_count?: number;
|
|
66
66
|
earliest_at?: string | null;
|
|
67
67
|
latest_at?: string | null;
|
|
68
|
-
/**
|
|
68
|
+
/** 1 when this summary row has at least one child invalidated,
|
|
69
69
|
* superseded, forgotten, or archived since it was last rebuilt. Cleared
|
|
70
|
-
* by
|
|
71
|
-
* rows (dag_level !== 2
|
|
70
|
+
* by rebuildDirtySummaries during sleep. Always 0 for non-summary
|
|
71
|
+
* rows (dag_level !== 2). */
|
|
72
72
|
summary_dirty?: 0 | 1;
|
|
73
|
-
/**
|
|
73
|
+
/** ISO 8601 timestamp of the last successful rebuild for this
|
|
74
74
|
* summary, or null if never rebuilt. */
|
|
75
75
|
last_rebuilt_at?: string | null;
|
|
76
|
-
/**
|
|
77
|
-
* summary. 0 for initial buildDag write; bumped by
|
|
76
|
+
/** Monotonically-increasing counter of successful rebuilds for this
|
|
77
|
+
* summary. 0 for initial buildDag write; bumped by each rebuild. */
|
|
78
78
|
rebuild_count?: number;
|
|
79
|
-
/**
|
|
79
|
+
/** Reserved: ISO 8601 timestamp the level-3 entity profile
|
|
80
80
|
* was built. Only ever populated on dag_level=3 rows. */
|
|
81
81
|
dag_level_3_built_at?: string | null;
|
|
82
82
|
kind: MemoryKind;
|
|
@@ -85,16 +85,16 @@ export interface MemoryEntry {
|
|
|
85
85
|
artifact_ref: string | null;
|
|
86
86
|
tenantId: string;
|
|
87
87
|
/**
|
|
88
|
-
* Memory scope isolation
|
|
88
|
+
* Memory scope isolation: owning project for ambient-context
|
|
89
89
|
* partitioning. A lowercased project name, '' for user-global (injectable
|
|
90
|
-
* everywhere), or null for legacy
|
|
91
|
-
* null as other-project (deny). Stamped from the store's location
|
|
92
|
-
* time (store.ts stampOriginProject); undefined only on entries not yet
|
|
93
|
-
* written.
|
|
90
|
+
* everywhere), or null for legacy rows written before the column - ambient
|
|
91
|
+
* context treats null as other-project (deny). Stamped from the store's location
|
|
92
|
+
* at write time (store.ts stampOriginProject); undefined only on entries not yet
|
|
93
|
+
* written.
|
|
94
94
|
*/
|
|
95
95
|
origin_project?: string | null;
|
|
96
96
|
/**
|
|
97
|
-
*
|
|
97
|
+
* Raw SQLite FTS5 bm25() score from the FTS path of
|
|
98
98
|
* `loadSearchEntries`.
|
|
99
99
|
*
|
|
100
100
|
* Populated ONLY when ALL of the following hold:
|
|
@@ -113,7 +113,7 @@ export interface MemoryEntry {
|
|
|
113
113
|
*/
|
|
114
114
|
bm25_score?: number;
|
|
115
115
|
}
|
|
116
|
-
/**
|
|
116
|
+
/** Tag on a memory whose named file/symbol/script changed after it was stored. */
|
|
117
117
|
export declare const CHURN_STALE_TAG = "churn-stale";
|
|
118
118
|
/**
|
|
119
119
|
* Test-only helper. Tests that mutate `process.env.HIPPO_LOSS_AVERSION_RATIO`
|
|
@@ -144,9 +144,9 @@ export declare function calculateRewardFactor(entry: Pick<MemoryEntry, 'outcome_
|
|
|
144
144
|
export declare function netWrong(entry: Pick<MemoryEntry, 'outcome_positive' | 'outcome_negative'>): number;
|
|
145
145
|
/**
|
|
146
146
|
* Options for decay basis.
|
|
147
|
-
* - clock: wall-clock time (default
|
|
147
|
+
* - clock: wall-clock time (former default)
|
|
148
148
|
* - session: decay by sleep cycle count (for intermittent agents)
|
|
149
|
-
* - adaptive: auto-scale half-life by session frequency (default
|
|
149
|
+
* - adaptive: auto-scale half-life by session frequency (default)
|
|
150
150
|
*/
|
|
151
151
|
/** What calculateStrength reads, so a caller can score a row without loading its text. */
|
|
152
152
|
export type StrengthInputs = Pick<MemoryEntry, 'pinned' | 'created' | 'last_retrieved' | 'half_life_days' | 'retrieval_count' | 'emotional_valence' | 'outcome_positive' | 'outcome_negative'>;
|
|
@@ -211,10 +211,8 @@ export declare function confidenceLabel(entry: MemoryEntry, now?: Date): {
|
|
|
211
211
|
export declare function resolveConfidence(entry: MemoryEntry, now?: Date): ConfidenceLevel;
|
|
212
212
|
/**
|
|
213
213
|
* Base half-life for a new memory, in days, before `deriveHalfLife`'s
|
|
214
|
-
* write-time multipliers. 365
|
|
215
|
-
*
|
|
216
|
-
* lost the current fact far more often (29% vs 75% in the top five), and
|
|
217
|
-
* 730 days and decay off tied with 365. `hippo sleep` moves memories still
|
|
214
|
+
* write-time multipliers. 365 because 7 days lost the current fact far more
|
|
215
|
+
* often, and 730 days or no decay did no better. `hippo sleep` moves memories still
|
|
218
216
|
* on an older base (src/half-life-migration.ts).
|
|
219
217
|
*/
|
|
220
218
|
export declare const DEFAULT_HALF_LIFE_DAYS = 365;
|
package/dist/memory.js
CHANGED
|
@@ -14,19 +14,10 @@ export var Layer;
|
|
|
14
14
|
Layer["Semantic"] = "semantic";
|
|
15
15
|
Layer["Trace"] = "trace";
|
|
16
16
|
})(Layer || (Layer = {}));
|
|
17
|
-
/**
|
|
17
|
+
/** Tag on a memory whose named file/symbol/script changed after it was stored. */
|
|
18
18
|
export const CHURN_STALE_TAG = 'churn-stale';
|
|
19
|
-
// Emotional multipliers from PLAN.md.
|
|
20
|
-
//
|
|
21
|
-
// v1.13.5 / J5 loss-aversion calibration (Lovallo-Kahneman TFAS empirics:
|
|
22
|
-
// losses ~2x larger than equivalent gains). Defaults rebalanced:
|
|
23
|
-
// - positive (success-tagged): 1.3 -> 1.0
|
|
24
|
-
// - negative (error-tagged): 1.5 -> 2.0
|
|
25
|
-
// - critical stays at 2.0 (literal roadmap reading; J5 silent on critical;
|
|
26
|
-
// ranking signal in consolidate.ts/salience.ts/ambient.ts unchanged)
|
|
27
|
-
// - neutral stays at 1.0
|
|
28
|
-
//
|
|
29
|
-
// `negative` is further scaled per-process by HIPPO_LOSS_AVERSION_RATIO
|
|
19
|
+
// Emotional multipliers from PLAN.md. Losses weigh ~2x equivalent gains (Lovallo-Kahneman TFAS empirics),
|
|
20
|
+
// so negative is 2.0. `negative` is further scaled per-process by HIPPO_LOSS_AVERSION_RATIO
|
|
30
21
|
// (env var, default 1.0; see getLossAversionRatio + applyLossAversionRatio).
|
|
31
22
|
const EMOTIONAL_MULTIPLIERS = {
|
|
32
23
|
neutral: 1.0,
|
|
@@ -35,7 +26,7 @@ const EMOTIONAL_MULTIPLIERS = {
|
|
|
35
26
|
critical: 2.0,
|
|
36
27
|
};
|
|
37
28
|
/**
|
|
38
|
-
*
|
|
29
|
+
* Module-level lazy-cached read of HIPPO_LOSS_AVERSION_RATIO.
|
|
39
30
|
*
|
|
40
31
|
* `calculateStrength` is called per-entry inside hot recall loops
|
|
41
32
|
* (api.ts/consolidate.ts/search.ts), so a per-call `process.env` lookup
|
|
@@ -44,20 +35,19 @@ const EMOTIONAL_MULTIPLIERS = {
|
|
|
44
35
|
* Test isolation via `_resetLossAversionRatioCacheForTests()` below.
|
|
45
36
|
*/
|
|
46
37
|
/**
|
|
47
|
-
*
|
|
38
|
+
* Minimum acceptable ratio. Below this, the negative multiplier
|
|
48
39
|
* (2.0 * ratio) becomes small enough that calculateStrength * decay can fall
|
|
49
40
|
* below `DECAY_THRESHOLD = 0.05` in `src/consolidate.ts:146`, which would
|
|
50
41
|
* permanently delete non-pinned error-tagged memories on the next sleep
|
|
51
|
-
* cycle. 0.5 is chosen as the floor because (a) it recovers the
|
|
42
|
+
* cycle. 0.5 is chosen as the floor because (a) it recovers the pre-calibration
|
|
52
43
|
* effective multiplier (2.0 * 0.5 = 1.0 + the negative premium, i.e. 1.5x
|
|
53
|
-
* the
|
|
44
|
+
* the pre-calibration default), and (b) below this the user is asking for LESS
|
|
54
45
|
* loss aversion than has ever shipped — that's outside the supported
|
|
55
|
-
* tuning range.
|
|
46
|
+
* tuning range.
|
|
56
47
|
*/
|
|
57
48
|
const LOSS_AVERSION_RATIO_MIN = 0.5;
|
|
58
49
|
/**
|
|
59
|
-
* Validation policy
|
|
60
|
-
* round-1 P1 folds):
|
|
50
|
+
* Validation policy:
|
|
61
51
|
* - Valid: finite numbers >= 0.5.
|
|
62
52
|
* - Invalid (silent fallback to 1.0): empty string, non-numeric,
|
|
63
53
|
* numbers below 0.5 (including 0 and negatives), NaN, +/-Infinity.
|
|
@@ -65,17 +55,16 @@ const LOSS_AVERSION_RATIO_MIN = 0.5;
|
|
|
65
55
|
* on a typo.
|
|
66
56
|
*
|
|
67
57
|
* Why the 0.5 floor and not 0:
|
|
68
|
-
* -
|
|
69
|
-
* HIGH fold) leaves the same silent data-loss surface for any ratio
|
|
58
|
+
* - Rejecting only `0` leaves the same silent data-loss surface for any ratio
|
|
70
59
|
* below ~0.025 (and worse for aged memories, where even ratio=0.25
|
|
71
60
|
* can produce strength < DECAY_THRESHOLD = 0.05 in consolidate.ts).
|
|
72
|
-
* Floor at the
|
|
61
|
+
* Floor at the pre-calibration equivalent (0.5) so the env var's tuning
|
|
73
62
|
* range never crosses into the deletion regime.
|
|
74
|
-
* - Users wanting LESS loss aversion than
|
|
75
|
-
* should reconsider the design intent
|
|
63
|
+
* - Users wanting LESS loss aversion than the pre-calibration 1.5 multiplier
|
|
64
|
+
* should reconsider the design intent (the calibration was
|
|
76
65
|
* toward MORE loss aversion, not less). If a future use case
|
|
77
66
|
* genuinely needs ratio < 0.5, the right path is a separate
|
|
78
|
-
* `HIPPO_NEGATIVE_MULTIPLIER` env override
|
|
67
|
+
* `HIPPO_NEGATIVE_MULTIPLIER` env override.
|
|
79
68
|
*/
|
|
80
69
|
let _lossAversionRatioCache;
|
|
81
70
|
function getLossAversionRatio() {
|
|
@@ -111,8 +100,7 @@ export function _resetLossAversionRatioCacheForTests() {
|
|
|
111
100
|
/**
|
|
112
101
|
* Apply the loss-aversion ratio scalar to the `negative` multiplier ONLY.
|
|
113
102
|
* Other valences (positive, critical, neutral) pass through unchanged.
|
|
114
|
-
* `critical` is deliberately NOT scaled
|
|
115
|
-
* its multiplier is left alone so the calibration only touches the
|
|
103
|
+
* `critical` is deliberately NOT scaled, so the calibration only touches the
|
|
116
104
|
* specific empirical claim (TFAS 2x losses-vs-gains).
|
|
117
105
|
*/
|
|
118
106
|
function applyLossAversionRatio(valence, baseMultiplier) {
|
|
@@ -172,13 +160,9 @@ now = evalNow(), options = {}) {
|
|
|
172
160
|
const wrongPenalty = Math.pow(0.5, Math.min(netWrong(entry), MAX_WRONG_HALVINGS));
|
|
173
161
|
if (entry.pinned)
|
|
174
162
|
return wrongPenalty;
|
|
175
|
-
// EVAL-ONLY ablation (see ablation.ts):
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
// persisted by PRIOR unflagged runs leak strengthening into an ablated
|
|
179
|
-
// arm's rankings (codex P2). Identity on fresh stores (created ==
|
|
180
|
-
// last_retrieved at write). Prior-run half_life increments are NOT
|
|
181
|
-
// reconstructed - see the ablation.ts caveat (fresh stores per arm).
|
|
163
|
+
// EVAL-ONLY ablation (see ablation.ts): anchor decay at CREATION, so clock resets persisted by PRIOR
|
|
164
|
+
// unflagged runs cannot leak strengthening into an ablated arm. Prior-run half_life increments are
|
|
165
|
+
// NOT reconstructed - see the ablation.ts caveat (fresh stores per arm).
|
|
182
166
|
const lastRetrieved = new Date(isRecallBoostAblated() ? entry.created : entry.last_retrieved);
|
|
183
167
|
const daysSince = (now.getTime() - lastRetrieved.getTime()) / (1000 * 60 * 60 * 24);
|
|
184
168
|
// Reward-proportional half-life modulation
|
|
@@ -212,19 +196,13 @@ now = evalNow(), options = {}) {
|
|
|
212
196
|
// clamp below then caps retrievalBoost at baseline - see ablation.ts
|
|
213
197
|
// formula note.
|
|
214
198
|
const decay = isDecayAblated() ? 1.0 : Math.pow(0.5, decayExponent);
|
|
215
|
-
// Retrieval boost: 1 + 0.1 * log2(retrieval_count + 1)
|
|
216
|
-
//
|
|
217
|
-
// the READ side too, so a store with PRIOR retrieval history (counts > 0
|
|
218
|
-
// written before the flag was set) does not leak strengthening into an
|
|
219
|
-
// ablated arm's rankings (codex P2).
|
|
199
|
+
// Retrieval boost: 1 + 0.1 * log2(retrieval_count + 1). EVAL-ONLY ablation (see ablation.ts) neutralizes
|
|
200
|
+
// the READ side too, so counts written before the flag cannot leak strengthening into an ablated arm.
|
|
220
201
|
const retrievalBoost = isRecallBoostAblated() || netWrong(entry) > 0
|
|
221
202
|
? 1.0
|
|
222
203
|
: 1 + 0.1 * Math.log2(entry.retrieval_count + 1);
|
|
223
|
-
// Emotional multiplier
|
|
224
|
-
//
|
|
225
|
-
// ONLY (positive/critical/neutral pass through unchanged). Lazy module-cache
|
|
226
|
-
// means this is a single Map lookup + one numeric multiply, not a per-call
|
|
227
|
-
// process.env read.
|
|
204
|
+
// Emotional multiplier. HIPPO_LOSS_AVERSION_RATIO scales the negative one ONLY; the lazy
|
|
205
|
+
// module cache makes this one lookup + one multiply, not a per-call process.env read.
|
|
228
206
|
const baseMultiplier = EMOTIONAL_MULTIPLIERS[entry.emotional_valence] ?? 1.0;
|
|
229
207
|
const emotionalMultiplier = applyLossAversionRatio(entry.emotional_valence, baseMultiplier);
|
|
230
208
|
const raw = decay * retrievalBoost * emotionalMultiplier;
|
|
@@ -335,10 +313,8 @@ export function resolveConfidence(entry, now = evalNow()) {
|
|
|
335
313
|
}
|
|
336
314
|
/**
|
|
337
315
|
* Base half-life for a new memory, in days, before `deriveHalfLife`'s
|
|
338
|
-
* write-time multipliers. 365
|
|
339
|
-
*
|
|
340
|
-
* lost the current fact far more often (29% vs 75% in the top five), and
|
|
341
|
-
* 730 days and decay off tied with 365. `hippo sleep` moves memories still
|
|
316
|
+
* write-time multipliers. 365 because 7 days lost the current fact far more
|
|
317
|
+
* often, and 730 days or no decay did no better. `hippo sleep` moves memories still
|
|
342
318
|
* on an older base (src/half-life-migration.ts).
|
|
343
319
|
*/
|
|
344
320
|
export const DEFAULT_HALF_LIFE_DAYS = 365;
|
package/dist/multihop.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MemoryEntry } from './memory.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type ResultCost, type SearchResult } from './search/types.js';
|
|
3
3
|
export declare function multihopSearch(query: string, entries: MemoryEntry[], options?: {
|
|
4
4
|
budget?: number;
|
|
5
5
|
now?: Date;
|
package/dist/multihop.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { fitBudget } from './search/finalize.js';
|
|
2
2
|
import { search } from './search/bm25-search.js';
|
|
3
|
+
import { DEFAULT_RECALL_BUDGET } from './search/types.js';
|
|
3
4
|
export function multihopSearch(query, entries, options = {}) {
|
|
4
|
-
const budget = options.budget ??
|
|
5
|
+
const budget = options.budget ?? DEFAULT_RECALL_BUDGET;
|
|
5
6
|
// Pass 1 searches wide to find entities, so each return fits the caller's budget, as search() does.
|
|
6
7
|
const fit = (ordered) => fitBudget(ordered, budget, options.minResults ?? 1, options.cost);
|
|
7
8
|
const pass1 = search(query, entries, { ...options, budget: budget * 2 });
|
|
@@ -31,7 +32,7 @@ export function multihopSearch(query, entries, options = {}) {
|
|
|
31
32
|
merged.set(r.entry.id, r);
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
|
-
//
|
|
35
|
+
// PLAIN stable score sort on purpose -- pass1/pass2 inputs are
|
|
35
36
|
// deterministically ordered (search() carries the content tail), stability
|
|
36
37
|
// inherits that, and ties keep pass-1 results ahead of pass-2 follow-ups.
|
|
37
38
|
return fit([...merged.values()].sort((a, b) => b.score - a.score));
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* --owner format validation
|
|
2
|
+
* --owner format validation.
|
|
3
3
|
*
|
|
4
4
|
* Documented MEMORY_ENVELOPE.md contract: owner = `user:<id>` | `agent:<id>`
|
|
5
|
-
* with id ∈ `[A-Za-z0-9_-]+`.
|
|
6
|
-
* the documented contract unenforced.
|
|
5
|
+
* with id ∈ `[A-Za-z0-9_-]+`.
|
|
7
6
|
*
|
|
8
7
|
* Default: WARN-ONLY (log + accept) to preserve back-compat with existing
|
|
9
8
|
* scripted callers passing legacy owner strings. Set `HIPPO_STRICT_OWNER=1`
|
|
10
|
-
* to reject + exit. Strict mode will become the default once
|
|
11
|
-
* (see `TODOS.md`
|
|
9
|
+
* to reject + exit. Strict mode will become the default once real auth replaces
|
|
10
|
+
* the stub (see `TODOS.md` for the migration path).
|
|
12
11
|
*/
|
|
13
12
|
export declare const OWNER_RE: RegExp;
|
|
14
13
|
export declare const OWNER_CONTRACT_HINT = "Must match ^(user|agent):[A-Za-z0-9_-]+$ (e.g. user:alice, agent:capture-bot).";
|
package/dist/owner-validation.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* --owner format validation
|
|
2
|
+
* --owner format validation.
|
|
3
3
|
*
|
|
4
4
|
* Documented MEMORY_ENVELOPE.md contract: owner = `user:<id>` | `agent:<id>`
|
|
5
|
-
* with id ∈ `[A-Za-z0-9_-]+`.
|
|
6
|
-
* the documented contract unenforced.
|
|
5
|
+
* with id ∈ `[A-Za-z0-9_-]+`.
|
|
7
6
|
*
|
|
8
7
|
* Default: WARN-ONLY (log + accept) to preserve back-compat with existing
|
|
9
8
|
* scripted callers passing legacy owner strings. Set `HIPPO_STRICT_OWNER=1`
|
|
10
|
-
* to reject + exit. Strict mode will become the default once
|
|
11
|
-
* (see `TODOS.md`
|
|
9
|
+
* to reject + exit. Strict mode will become the default once real auth replaces
|
|
10
|
+
* the stub (see `TODOS.md` for the migration path).
|
|
12
11
|
*/
|
|
13
12
|
import { processEnv } from './env.js';
|
|
14
13
|
export const OWNER_RE = /^(user|agent):[A-Za-z0-9_-]+$/;
|