@remnic/core 9.3.628 → 9.3.630
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/dist/access-cli.js +18 -18
- package/dist/access-http.d.ts +6 -4
- package/dist/access-http.js +7 -6
- package/dist/access-mcp.d.ts +6 -4
- package/dist/access-mcp.js +6 -5
- package/dist/{access-service-C_sfOHsX.d.ts → access-service-C4v-eFjB.d.ts} +2 -2
- package/dist/access-service.d.ts +6 -4
- package/dist/access-service.js +5 -4
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +6 -4
- package/dist/briefing.d.ts +33 -2
- package/dist/briefing.js +5 -2
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/calibration.js +2 -2
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +5 -5
- package/dist/{chunk-GE7Q7KXP.js → chunk-2VJ7AJFX.js} +2 -2
- package/dist/{chunk-KVFYTRMV.js → chunk-4QEUKASL.js} +2 -2
- package/dist/{chunk-KB4MFBF5.js → chunk-5S6IREG3.js} +3 -3
- package/dist/{chunk-LQYTQCXM.js → chunk-6LBQL5US.js} +2 -2
- package/dist/{chunk-KGIGRNR6.js → chunk-723OMPUI.js} +4 -4
- package/dist/{chunk-TZDSNIRO.js → chunk-ADOD7PJC.js} +5 -5
- package/dist/{chunk-SHV5Y2WU.js → chunk-BL33LBTN.js} +3 -3
- package/dist/{chunk-532VCWYW.js → chunk-BWK5EEKS.js} +2 -2
- package/dist/{chunk-KKTXCFD7.js → chunk-EORL2IDM.js} +39 -8
- package/dist/{chunk-KKTXCFD7.js.map → chunk-EORL2IDM.js.map} +1 -1
- package/dist/{chunk-F3FY3D3S.js → chunk-F6USGHMO.js} +10 -5
- package/dist/chunk-F6USGHMO.js.map +1 -0
- package/dist/{chunk-STDAAGH7.js → chunk-GXWFZYSR.js} +39 -3
- package/dist/chunk-GXWFZYSR.js.map +1 -0
- package/dist/{chunk-3VONWEQB.js → chunk-HZVIYZYN.js} +2 -2
- package/dist/{chunk-Y3TMFC6I.js → chunk-K3BTOW7N.js} +3 -3
- package/dist/{chunk-Z3CCEP6F.js → chunk-K47C6M2C.js} +5 -5
- package/dist/{chunk-N5RGXWLQ.js → chunk-MQ24KOOR.js} +2 -2
- package/dist/{chunk-3MNBW7R7.js → chunk-NRQJBK36.js} +2 -2
- package/dist/{chunk-MON3LMO7.js → chunk-NRST7W5Q.js} +5 -5
- package/dist/{chunk-3R2UZV3U.js → chunk-OOFBE62K.js} +2 -2
- package/dist/{chunk-MVQN73GT.js → chunk-OQMR2SDZ.js} +2 -2
- package/dist/{chunk-UGHUNQ74.js → chunk-RSKUUEBA.js} +73 -1
- package/dist/chunk-RSKUUEBA.js.map +1 -0
- package/dist/{chunk-QDV6VAD4.js → chunk-S5W37FPX.js} +2 -2
- package/dist/{chunk-57QXN2CS.js → chunk-SACS6KE6.js} +2 -2
- package/dist/{chunk-UELS6WWF.js → chunk-UE57H4MA.js} +2 -2
- package/dist/{chunk-2RHI3FGV.js → chunk-VUTPRX7K.js} +20 -14
- package/dist/{chunk-2RHI3FGV.js.map → chunk-VUTPRX7K.js.map} +1 -1
- package/dist/{chunk-AZ4RI3QD.js → chunk-YJOWWRRS.js} +450 -48
- package/dist/chunk-YJOWWRRS.js.map +1 -0
- package/dist/{chunk-P2D2MM47.js → chunk-ZZSXUZF3.js} +2 -2
- package/dist/{cli-EZv6YE6_.d.ts → cli-B_6EMiQc.d.ts} +3 -3
- package/dist/cli.d.ts +7 -5
- package/dist/cli.js +18 -17
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +2 -2
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +2 -2
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +2 -2
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +2 -2
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +6 -4
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction-judge.js +3 -3
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +3 -3
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/fallback-llm.js +2 -2
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.js +29 -27
- package/dist/index.js.map +1 -1
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +6 -4
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +1 -1
- package/dist/namespaces/migrate.js +3 -3
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/storage.d.ts +1 -1
- package/dist/namespaces/storage.js +2 -2
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +6 -6
- package/dist/{orchestrator-CEycaY3M.d.ts → orchestrator-Dlw3ae4B.d.ts} +111 -10
- package/dist/orchestrator.d.ts +5 -3
- package/dist/orchestrator.js +15 -14
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-planner-llm.js +2 -2
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +2 -2
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/schemas.d.ts +24 -24
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/index.d.ts +1 -1
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-FbhPeJjB.d.ts → semantic-consolidation-C4sefXEI.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +3 -3
- package/dist/semantic-rule-promotion.js +2 -2
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +2 -2
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +38 -2
- package/dist/storage.js +5 -3
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +3 -3
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/types.d.ts +12 -12
- package/dist/{types-D5VRAI04.d.ts → types-2vqxmO0j.d.ts} +39 -10
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +2 -2
- package/package.json +1 -1
- package/src/access-service.ts +7 -0
- package/src/briefing.ts +67 -1
- package/src/index.ts +2 -0
- package/src/orchestrator.ts +42 -0
- package/src/storage.ts +100 -0
- package/src/wearables/cli.ts +6 -0
- package/src/wearables/config.test.ts +33 -4
- package/src/wearables/config.ts +39 -7
- package/src/wearables/memory-gen.test.ts +416 -1
- package/src/wearables/memory-gen.ts +381 -23
- package/src/wearables/pipeline.test.ts +309 -1
- package/src/wearables/pipeline.ts +131 -9
- package/src/wearables/service.test.ts +172 -0
- package/src/wearables/service.ts +84 -3
- package/src/wearables/storage-io.test.ts +81 -0
- package/src/wearables/trust.test.ts +123 -0
- package/src/wearables/trust.ts +168 -0
- package/src/wearables/types.ts +37 -8
- package/dist/chunk-AZ4RI3QD.js.map +0 -1
- package/dist/chunk-F3FY3D3S.js.map +0 -1
- package/dist/chunk-STDAAGH7.js.map +0 -1
- package/dist/chunk-UGHUNQ74.js.map +0 -1
- /package/dist/{chunk-GE7Q7KXP.js.map → chunk-2VJ7AJFX.js.map} +0 -0
- /package/dist/{chunk-KVFYTRMV.js.map → chunk-4QEUKASL.js.map} +0 -0
- /package/dist/{chunk-KB4MFBF5.js.map → chunk-5S6IREG3.js.map} +0 -0
- /package/dist/{chunk-LQYTQCXM.js.map → chunk-6LBQL5US.js.map} +0 -0
- /package/dist/{chunk-KGIGRNR6.js.map → chunk-723OMPUI.js.map} +0 -0
- /package/dist/{chunk-TZDSNIRO.js.map → chunk-ADOD7PJC.js.map} +0 -0
- /package/dist/{chunk-SHV5Y2WU.js.map → chunk-BL33LBTN.js.map} +0 -0
- /package/dist/{chunk-532VCWYW.js.map → chunk-BWK5EEKS.js.map} +0 -0
- /package/dist/{chunk-3VONWEQB.js.map → chunk-HZVIYZYN.js.map} +0 -0
- /package/dist/{chunk-Y3TMFC6I.js.map → chunk-K3BTOW7N.js.map} +0 -0
- /package/dist/{chunk-Z3CCEP6F.js.map → chunk-K47C6M2C.js.map} +0 -0
- /package/dist/{chunk-N5RGXWLQ.js.map → chunk-MQ24KOOR.js.map} +0 -0
- /package/dist/{chunk-3MNBW7R7.js.map → chunk-NRQJBK36.js.map} +0 -0
- /package/dist/{chunk-MON3LMO7.js.map → chunk-NRST7W5Q.js.map} +0 -0
- /package/dist/{chunk-3R2UZV3U.js.map → chunk-OOFBE62K.js.map} +0 -0
- /package/dist/{chunk-MVQN73GT.js.map → chunk-OQMR2SDZ.js.map} +0 -0
- /package/dist/{chunk-QDV6VAD4.js.map → chunk-S5W37FPX.js.map} +0 -0
- /package/dist/{chunk-57QXN2CS.js.map → chunk-SACS6KE6.js.map} +0 -0
- /package/dist/{chunk-UELS6WWF.js.map → chunk-UE57H4MA.js.map} +0 -0
- /package/dist/{chunk-P2D2MM47.js.map → chunk-ZZSXUZF3.js.map} +0 -0
|
@@ -28,7 +28,16 @@
|
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
import { scoreImportance } from "../importance.js";
|
|
31
|
+
import type { JudgeBatchResult, JudgeCandidate } from "../extraction-judge.js";
|
|
32
|
+
import { getVerdictKind } from "../extraction-judge.js";
|
|
31
33
|
import { describeErrorForOperator } from "./errors.js";
|
|
34
|
+
import {
|
|
35
|
+
computeTrustScore,
|
|
36
|
+
decideSmart,
|
|
37
|
+
findCorroboration,
|
|
38
|
+
type CorroborationContext,
|
|
39
|
+
type TrustEvidence,
|
|
40
|
+
} from "./trust.js";
|
|
32
41
|
import type {
|
|
33
42
|
BufferTurn,
|
|
34
43
|
ExtractedFact,
|
|
@@ -54,7 +63,7 @@ import type {
|
|
|
54
63
|
export function memoryStatusForMode(
|
|
55
64
|
mode: WearableMemoryMode,
|
|
56
65
|
): Extract<MemoryStatus, "active" | "pending_review"> {
|
|
57
|
-
return mode === "auto" ? "active" : "pending_review";
|
|
66
|
+
return mode === "auto" || mode === "smart" ? "active" : "pending_review";
|
|
58
67
|
}
|
|
59
68
|
|
|
60
69
|
/** Narrow writer interface satisfied by `StorageManager`. */
|
|
@@ -75,19 +84,70 @@ export interface WearableMemoryWriter {
|
|
|
75
84
|
},
|
|
76
85
|
): Promise<string>;
|
|
77
86
|
hasFactContentHash(content: string): Promise<boolean>;
|
|
87
|
+
/**
|
|
88
|
+
* Locate an earlier wearable write of the same content (any status).
|
|
89
|
+
* Optional: enables in-place promotion when re-scoring with stronger
|
|
90
|
+
* evidence.
|
|
91
|
+
*/
|
|
92
|
+
findWearableMemoryByContent?(
|
|
93
|
+
content: string,
|
|
94
|
+
): Promise<{ id: string; status: MemoryStatus | undefined } | null>;
|
|
95
|
+
/**
|
|
96
|
+
* Promote a pending_review wearable memory to active, merging trust
|
|
97
|
+
* evidence. Returns false when missing or no longer pending.
|
|
98
|
+
*/
|
|
99
|
+
promoteWearableMemory?(
|
|
100
|
+
id: string,
|
|
101
|
+
attributeUpdates: Record<string, string>,
|
|
102
|
+
confidence?: number,
|
|
103
|
+
): Promise<boolean>;
|
|
104
|
+
/**
|
|
105
|
+
* Demote a pending_review wearable memory to rejected on an explicit
|
|
106
|
+
* judge-reject re-verdict. Returns false when missing or no longer
|
|
107
|
+
* pending. Active rows are never auto-demoted.
|
|
108
|
+
*/
|
|
109
|
+
demoteWearableMemory?(
|
|
110
|
+
id: string,
|
|
111
|
+
attributeUpdates: Record<string, string>,
|
|
112
|
+
): Promise<boolean>;
|
|
78
113
|
}
|
|
79
114
|
|
|
80
115
|
export interface WearableMemoryGenDeps {
|
|
81
116
|
extract(turns: BufferTurn[]): Promise<ExtractionResult>;
|
|
82
117
|
writer: WearableMemoryWriter;
|
|
118
|
+
/**
|
|
119
|
+
* LLM-as-judge batch evaluation (the existing extraction judge).
|
|
120
|
+
* Absent when no judge is wired (degraded smart mode: trust scoring
|
|
121
|
+
* runs on confidence x sourceTrust + corroboration alone).
|
|
122
|
+
*/
|
|
123
|
+
judgeFacts?(candidates: JudgeCandidate[]): Promise<JudgeBatchResult>;
|
|
124
|
+
/**
|
|
125
|
+
* Corroboration evidence for smart mode: other sources' same-day
|
|
126
|
+
* transcript tokens + existing active memories. Absent disables
|
|
127
|
+
* corroboration boosts.
|
|
128
|
+
*/
|
|
129
|
+
corroboration?: CorroborationContext;
|
|
83
130
|
}
|
|
84
131
|
|
|
85
132
|
export interface WearableMemoryGenResult {
|
|
86
133
|
created: number;
|
|
134
|
+
/** Earlier borderline writes promoted to active by new evidence. */
|
|
135
|
+
promoted: number;
|
|
136
|
+
/** Earlier pending writes retired by a fresh judge-reject verdict. */
|
|
137
|
+
demoted: number;
|
|
87
138
|
skipped: number;
|
|
88
139
|
skippedByReason: Record<string, number>;
|
|
89
140
|
/** Non-fatal problems (e.g. the extraction engine erroring). */
|
|
90
141
|
warnings: string[];
|
|
142
|
+
/**
|
|
143
|
+
* True when every conversation was extracted (the pass may still
|
|
144
|
+
* carry degraded-mode warnings, e.g. judge unavailable). False only
|
|
145
|
+
* when extraction itself aborted mid-day — the signal callers use to
|
|
146
|
+
* re-run the pass on the next sync. A degraded-but-complete pass
|
|
147
|
+
* must NOT re-run forever: its facts are already written and dedup
|
|
148
|
+
* would suppress improvements anyway.
|
|
149
|
+
*/
|
|
150
|
+
completed: boolean;
|
|
91
151
|
}
|
|
92
152
|
|
|
93
153
|
export const WEARABLE_SOURCE_PREFIX = "wearable";
|
|
@@ -171,6 +231,70 @@ interface GatedCandidate {
|
|
|
171
231
|
conversation: WearableConversation;
|
|
172
232
|
}
|
|
173
233
|
|
|
234
|
+
interface ScoredCandidate {
|
|
235
|
+
trust: number;
|
|
236
|
+
verdict?: "accept" | "reject" | "defer";
|
|
237
|
+
evidence: TrustEvidence;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Smart-mode scoring: one judge batch call for the whole day, then
|
|
242
|
+
* per-fact trust = confidence x sourceTrust + judge/corroboration
|
|
243
|
+
* boosts. A judge failure degrades gracefully (warned once; scoring
|
|
244
|
+
* continues on confidence + corroboration alone).
|
|
245
|
+
*/
|
|
246
|
+
async function scoreCandidates(
|
|
247
|
+
novel: GatedCandidate[],
|
|
248
|
+
settings: WearableSourceSettings,
|
|
249
|
+
deps: WearableMemoryGenDeps,
|
|
250
|
+
result: WearableMemoryGenResult,
|
|
251
|
+
): Promise<Map<number, ScoredCandidate>> {
|
|
252
|
+
const scored = new Map<number, ScoredCandidate>();
|
|
253
|
+
if (novel.length === 0) return scored;
|
|
254
|
+
|
|
255
|
+
let verdicts: Map<number, "accept" | "reject" | "defer"> | undefined;
|
|
256
|
+
if (deps.judgeFacts) {
|
|
257
|
+
const judgeCandidates: JudgeCandidate[] = novel.map((candidate) => ({
|
|
258
|
+
text: candidate.fact.content,
|
|
259
|
+
category: candidate.fact.category,
|
|
260
|
+
confidence:
|
|
261
|
+
typeof candidate.fact.confidence === "number"
|
|
262
|
+
? candidate.fact.confidence
|
|
263
|
+
: 0.7,
|
|
264
|
+
tags: candidate.fact.tags ?? [],
|
|
265
|
+
importanceLevel: candidate.importance.level,
|
|
266
|
+
}));
|
|
267
|
+
try {
|
|
268
|
+
const judgeResult = await deps.judgeFacts(judgeCandidates);
|
|
269
|
+
verdicts = new Map();
|
|
270
|
+
for (const [index, verdict] of judgeResult.verdicts) {
|
|
271
|
+
verdicts.set(index, getVerdictKind(verdict));
|
|
272
|
+
}
|
|
273
|
+
} catch (err) {
|
|
274
|
+
result.warnings.push(
|
|
275
|
+
`extraction judge unavailable for this pass: ${describeErrorForOperator(err)} — trust scoring continued without judge verdicts`,
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const corroboration: CorroborationContext = deps.corroboration ?? {
|
|
281
|
+
otherSourceDayTokens: new Map(),
|
|
282
|
+
existingMemories: [],
|
|
283
|
+
};
|
|
284
|
+
novel.forEach((candidate, index) => {
|
|
285
|
+
const evidence = findCorroboration(candidate.fact.content, corroboration);
|
|
286
|
+
const verdict = verdicts?.get(index);
|
|
287
|
+
const trust = computeTrustScore({
|
|
288
|
+
extractionConfidence: candidate.fact.confidence,
|
|
289
|
+
sourceTrust: settings.sourceTrust,
|
|
290
|
+
judgeVerdict: verdict,
|
|
291
|
+
evidence,
|
|
292
|
+
});
|
|
293
|
+
scored.set(index, { trust, ...(verdict !== undefined ? { verdict } : {}), evidence });
|
|
294
|
+
});
|
|
295
|
+
return scored;
|
|
296
|
+
}
|
|
297
|
+
|
|
174
298
|
/**
|
|
175
299
|
* Run extraction + gates over a day's conversations and persist the
|
|
176
300
|
* survivors. Returns counts for the sync summary.
|
|
@@ -185,9 +309,12 @@ export async function generateWearableMemories(
|
|
|
185
309
|
): Promise<WearableMemoryGenResult> {
|
|
186
310
|
const result: WearableMemoryGenResult = {
|
|
187
311
|
created: 0,
|
|
312
|
+
promoted: 0,
|
|
313
|
+
demoted: 0,
|
|
188
314
|
skipped: 0,
|
|
189
315
|
skippedByReason: {},
|
|
190
316
|
warnings: [],
|
|
317
|
+
completed: true,
|
|
191
318
|
};
|
|
192
319
|
if (settings.memoryMode === "off") return result;
|
|
193
320
|
|
|
@@ -215,6 +342,7 @@ export async function generateWearableMemories(
|
|
|
215
342
|
result.warnings.push(
|
|
216
343
|
`extraction failed for ${sourceId}/${date} (conversation ${conversation.id}): ${describeErrorForOperator(err)} — the memory pass for this day retries on the next sync`,
|
|
217
344
|
);
|
|
345
|
+
result.completed = false;
|
|
218
346
|
break;
|
|
219
347
|
}
|
|
220
348
|
for (const fact of extraction.facts) {
|
|
@@ -227,7 +355,11 @@ export async function generateWearableMemories(
|
|
|
227
355
|
skip("unsupported-category");
|
|
228
356
|
continue;
|
|
229
357
|
}
|
|
358
|
+
// In smart mode the trust bands subsume the hard confidence
|
|
359
|
+
// floor — a borderline fact belongs in the review band, not on
|
|
360
|
+
// the floor. The pre-filter applies to review/auto modes only.
|
|
230
361
|
if (
|
|
362
|
+
settings.memoryMode !== "smart" &&
|
|
231
363
|
typeof fact.confidence === "number" &&
|
|
232
364
|
fact.confidence < settings.minConfidence
|
|
233
365
|
) {
|
|
@@ -254,33 +386,177 @@ export async function generateWearableMemories(
|
|
|
254
386
|
|
|
255
387
|
// Drop candidates that already exist in storage BEFORE applying the
|
|
256
388
|
// day cap so duplicates never consume cap slots that novel,
|
|
257
|
-
// lower-scoring candidates should get (Codex P2 on PR #1458).
|
|
389
|
+
// lower-scoring candidates should get (Codex P2 on PR #1458). In
|
|
390
|
+
// smart mode a duplicate of a PENDING_REVIEW write is kept aside as
|
|
391
|
+
// a promotion candidate — corroboration that arrives after the
|
|
392
|
+
// original borderline write (another device syncing the same day)
|
|
393
|
+
// must be able to promote it in place (Cursor review on PR #1462).
|
|
258
394
|
const novel: GatedCandidate[] = [];
|
|
395
|
+
const promotable: GatedCandidate[] = [];
|
|
259
396
|
for (const candidate of candidates) {
|
|
260
397
|
if (await deps.writer.hasFactContentHash(candidate.fact.content)) {
|
|
261
|
-
|
|
398
|
+
if (
|
|
399
|
+
settings.memoryMode === "smart" &&
|
|
400
|
+
deps.writer.findWearableMemoryByContent !== undefined &&
|
|
401
|
+
deps.writer.promoteWearableMemory !== undefined
|
|
402
|
+
) {
|
|
403
|
+
promotable.push(candidate);
|
|
404
|
+
} else {
|
|
405
|
+
skip("duplicate-existing");
|
|
406
|
+
}
|
|
262
407
|
continue;
|
|
263
408
|
}
|
|
264
409
|
novel.push(candidate);
|
|
265
410
|
}
|
|
266
411
|
|
|
267
|
-
//
|
|
268
|
-
//
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
412
|
+
// Re-score promotion candidates with TODAY'S evidence; promote the
|
|
413
|
+
// ones that now clear the auto threshold. Never consumes day-cap
|
|
414
|
+
// slots (no new memory is written).
|
|
415
|
+
if (promotable.length > 0) {
|
|
416
|
+
const promoteScores = await scoreCandidates(promotable, settings, deps, result);
|
|
417
|
+
for (const [index, candidate] of promotable.entries()) {
|
|
418
|
+
const scored = promoteScores.get(index);
|
|
419
|
+
const decision = scored
|
|
420
|
+
? decideSmart(scored.trust, scored.verdict, settings)
|
|
421
|
+
: undefined;
|
|
422
|
+
if (!scored || !decision) {
|
|
423
|
+
skip("duplicate-existing");
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
// A fresh judge-REJECT retires the stored row — but only a
|
|
427
|
+
// pending_review one. Active rows are never auto-demoted: an
|
|
428
|
+
// operator approval or accrued recall signals must not be
|
|
429
|
+
// overturned by one later LLM verdict; contradiction scans and
|
|
430
|
+
// supersession own active-row retirement (Cursor review on PR
|
|
431
|
+
// #1462, round 7).
|
|
432
|
+
if (scored.verdict === "reject") {
|
|
433
|
+
if (deps.writer.demoteWearableMemory !== undefined) {
|
|
434
|
+
const existingForDemote = await deps.writer.findWearableMemoryByContent!(
|
|
435
|
+
candidate.fact.content,
|
|
436
|
+
);
|
|
437
|
+
if (
|
|
438
|
+
existingForDemote &&
|
|
439
|
+
existingForDemote.status === "pending_review" &&
|
|
440
|
+
(await deps.writer.demoteWearableMemory(existingForDemote.id, {
|
|
441
|
+
trustScore: scored.trust.toFixed(3),
|
|
442
|
+
trustDecision: "demoted-by-rejection",
|
|
443
|
+
judgeVerdict: "reject",
|
|
444
|
+
}))
|
|
445
|
+
) {
|
|
446
|
+
result.demoted += 1;
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
skip("duplicate-existing");
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
if (decision.outcome !== "active") {
|
|
454
|
+
skip("duplicate-existing");
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
const existing = await deps.writer.findWearableMemoryByContent!(
|
|
458
|
+
candidate.fact.content,
|
|
459
|
+
);
|
|
460
|
+
if (!existing || existing.status !== "pending_review") {
|
|
461
|
+
skip("duplicate-existing");
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
const promoted = await deps.writer.promoteWearableMemory!(
|
|
465
|
+
existing.id,
|
|
466
|
+
{
|
|
467
|
+
trustScore: scored.trust.toFixed(3),
|
|
468
|
+
trustDecision: "promoted-by-corroboration",
|
|
469
|
+
...(scored.verdict !== undefined ? { judgeVerdict: scored.verdict } : {}),
|
|
470
|
+
...(scored.evidence.corroboratedBySources.length > 0
|
|
471
|
+
? { corroboratedBySources: scored.evidence.corroboratedBySources.join(",") }
|
|
472
|
+
: {}),
|
|
473
|
+
...(scored.evidence.supportingMemoryId !== undefined
|
|
474
|
+
? { supportingMemoryId: scored.evidence.supportingMemoryId }
|
|
475
|
+
: {}),
|
|
476
|
+
},
|
|
477
|
+
scored.trust,
|
|
478
|
+
);
|
|
479
|
+
if (promoted) {
|
|
480
|
+
result.promoted += 1;
|
|
481
|
+
} else {
|
|
482
|
+
skip("duplicate-existing");
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Smart mode: judge + trust scoring decide active/review/drop per
|
|
488
|
+
// fact. The judge runs ONE batch call for the whole day; trust
|
|
489
|
+
// combines extraction confidence x sourceTrust with corroboration
|
|
490
|
+
// boosts (cross-device agreement, existing-memory support).
|
|
491
|
+
let trustById = new Map<number, ScoredCandidate>();
|
|
492
|
+
if (settings.memoryMode === "smart") {
|
|
493
|
+
trustById = await scoreCandidates(novel, settings, deps, result);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Smart decisions run BEFORE the day cap so dropped facts (judge
|
|
497
|
+
// rejections, below-trust) never consume cap slots that surviving
|
|
498
|
+
// candidates ranked past position N should get (Cursor review on PR
|
|
499
|
+
// #1462).
|
|
500
|
+
interface Writable {
|
|
501
|
+
candidate: GatedCandidate;
|
|
502
|
+
index: number;
|
|
503
|
+
status: MemoryStatus;
|
|
504
|
+
trustAttributes: Record<string, string>;
|
|
505
|
+
}
|
|
506
|
+
const modeStatus = memoryStatusForMode(settings.memoryMode);
|
|
507
|
+
const writable: Writable[] = [];
|
|
508
|
+
novel.forEach((candidate, index) => {
|
|
509
|
+
if (settings.memoryMode !== "smart") {
|
|
510
|
+
writable.push({ candidate, index, status: modeStatus, trustAttributes: {} });
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
const scored = trustById.get(index);
|
|
514
|
+
if (!scored) return;
|
|
515
|
+
const decision = decideSmart(scored.trust, scored.verdict, settings);
|
|
516
|
+
if (decision.outcome === "drop") {
|
|
517
|
+
skip(decision.reason);
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
writable.push({
|
|
521
|
+
candidate,
|
|
522
|
+
index,
|
|
523
|
+
status: decision.outcome === "active" ? "active" : "pending_review",
|
|
524
|
+
trustAttributes: {
|
|
525
|
+
trustScore: scored.trust.toFixed(3),
|
|
526
|
+
trustDecision: decision.reason,
|
|
527
|
+
...(scored.verdict !== undefined ? { judgeVerdict: scored.verdict } : {}),
|
|
528
|
+
...(scored.evidence.corroboratedBySources.length > 0
|
|
529
|
+
? { corroboratedBySources: scored.evidence.corroboratedBySources.join(",") }
|
|
530
|
+
: {}),
|
|
531
|
+
...(scored.evidence.supportingMemoryId !== undefined
|
|
532
|
+
? { supportingMemoryId: scored.evidence.supportingMemoryId }
|
|
533
|
+
: {}),
|
|
534
|
+
},
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
// Day cap over the SURVIVORS: strongest by trust in smart mode, by
|
|
539
|
+
// importance otherwise. Stable ordering with a content tiebreak.
|
|
540
|
+
const strength = (entry: Writable): number =>
|
|
541
|
+
settings.memoryMode === "smart"
|
|
542
|
+
? trustById.get(entry.index)?.trust ?? 0
|
|
543
|
+
: entry.candidate.importance.score;
|
|
544
|
+
writable.sort((a, b) => {
|
|
545
|
+
const sa = strength(a);
|
|
546
|
+
const sb = strength(b);
|
|
547
|
+
if (sa > sb) return -1;
|
|
548
|
+
if (sa < sb) return 1;
|
|
549
|
+
if (a.candidate.fact.content < b.candidate.fact.content) return -1;
|
|
550
|
+
if (a.candidate.fact.content > b.candidate.fact.content) return 1;
|
|
274
551
|
return 0;
|
|
275
552
|
});
|
|
276
553
|
const cap = settings.maxMemoriesPerDay;
|
|
277
|
-
const kept = cap > 0 ?
|
|
278
|
-
if (
|
|
279
|
-
skip("over-day-cap",
|
|
554
|
+
const kept = cap > 0 ? writable.slice(0, cap) : writable;
|
|
555
|
+
if (writable.length > kept.length) {
|
|
556
|
+
skip("over-day-cap", writable.length - kept.length);
|
|
280
557
|
}
|
|
281
558
|
|
|
282
|
-
const status
|
|
283
|
-
for (const candidate of kept) {
|
|
559
|
+
for (const { candidate, index, status, trustAttributes } of kept) {
|
|
284
560
|
const tags = [
|
|
285
561
|
...new Set([
|
|
286
562
|
...(candidate.fact.tags ?? []),
|
|
@@ -290,7 +566,10 @@ export async function generateWearableMemories(
|
|
|
290
566
|
]),
|
|
291
567
|
];
|
|
292
568
|
await deps.writer.writeMemory(candidate.fact.category, candidate.fact.content, {
|
|
293
|
-
confidence:
|
|
569
|
+
confidence:
|
|
570
|
+
settings.memoryMode === "smart"
|
|
571
|
+
? trustById.get(index)?.trust
|
|
572
|
+
: candidate.fact.confidence,
|
|
294
573
|
tags,
|
|
295
574
|
source: wearableSourceLabel(sourceId),
|
|
296
575
|
importance: candidate.importance,
|
|
@@ -300,6 +579,7 @@ export async function generateWearableMemories(
|
|
|
300
579
|
wearableSource: sourceId,
|
|
301
580
|
wearableDate: date,
|
|
302
581
|
wearableConversationId: candidate.conversation.id,
|
|
582
|
+
...trustAttributes,
|
|
303
583
|
},
|
|
304
584
|
contentHashSource: candidate.fact.content,
|
|
305
585
|
status,
|
|
@@ -365,15 +645,26 @@ export async function writeDailyDigestMemory(
|
|
|
365
645
|
* review queue. Always `pending_review` regardless of memoryMode — the
|
|
366
646
|
* provider's extraction quality is outside Remnic's control.
|
|
367
647
|
*/
|
|
648
|
+
/** Native-source trust prior reduction (provider extraction quality). */
|
|
649
|
+
const NATIVE_TRUST_FACTOR = 0.9;
|
|
650
|
+
|
|
368
651
|
export async function importNativeMemories(
|
|
369
652
|
sourceId: string,
|
|
370
653
|
memories: WearableNativeMemory[],
|
|
371
654
|
alreadyImportedIds: ReadonlySet<string>,
|
|
372
|
-
|
|
373
|
-
|
|
655
|
+
settings: WearableSourceSettings,
|
|
656
|
+
deps: WearableMemoryGenDeps,
|
|
657
|
+
): Promise<{ imported: number; importedIds: string[]; warnings: string[] }> {
|
|
374
658
|
let imported = 0;
|
|
375
659
|
const importedIds: string[] = [];
|
|
660
|
+
const warnings: string[] = [];
|
|
376
661
|
const seenContent = new Set<string>();
|
|
662
|
+
const smart = settings.importNativeMemories === "smart";
|
|
663
|
+
|
|
664
|
+
// Smart path: one judge batch over the novel items, like transcript
|
|
665
|
+
// facts, with a reduced source prior — provider extraction quality is
|
|
666
|
+
// outside Remnic's control.
|
|
667
|
+
const novel: WearableNativeMemory[] = [];
|
|
377
668
|
for (const memory of memories) {
|
|
378
669
|
const content = memory.content?.trim();
|
|
379
670
|
if (!content) continue;
|
|
@@ -381,13 +672,79 @@ export async function importNativeMemories(
|
|
|
381
672
|
// Intra-run + cross-run dedup: the storage hash index only learns a
|
|
382
673
|
// fact after its write lands, so same-content items within one page
|
|
383
674
|
// batch need the local set.
|
|
384
|
-
if (seenContent.has(content) || (await writer.hasFactContentHash(content))) {
|
|
675
|
+
if (seenContent.has(content) || (await deps.writer.hasFactContentHash(content))) {
|
|
385
676
|
importedIds.push(memory.id);
|
|
386
677
|
continue;
|
|
387
678
|
}
|
|
388
679
|
seenContent.add(content);
|
|
389
|
-
|
|
390
|
-
|
|
680
|
+
novel.push({ ...memory, content });
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
let verdicts: Map<number, "accept" | "reject" | "defer"> | undefined;
|
|
684
|
+
if (smart && deps.judgeFacts && novel.length > 0) {
|
|
685
|
+
try {
|
|
686
|
+
const judgeResult = await deps.judgeFacts(
|
|
687
|
+
novel.map((memory) => ({
|
|
688
|
+
text: memory.content,
|
|
689
|
+
category: "fact",
|
|
690
|
+
confidence: 0.7,
|
|
691
|
+
tags: memory.tags ?? [],
|
|
692
|
+
})),
|
|
693
|
+
);
|
|
694
|
+
verdicts = new Map();
|
|
695
|
+
for (const [index, verdict] of judgeResult.verdicts) {
|
|
696
|
+
verdicts.set(index, getVerdictKind(verdict));
|
|
697
|
+
}
|
|
698
|
+
} catch (err) {
|
|
699
|
+
warnings.push(
|
|
700
|
+
`extraction judge unavailable for native import: ${describeErrorForOperator(err)} — trust scoring continued without judge verdicts`,
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
const corroboration: CorroborationContext = deps.corroboration ?? {
|
|
705
|
+
otherSourceDayTokens: new Map(),
|
|
706
|
+
existingMemories: [],
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
for (const [index, memory] of novel.entries()) {
|
|
710
|
+
const content = memory.content;
|
|
711
|
+
let status: MemoryStatus = "pending_review";
|
|
712
|
+
let trustAttributes: Record<string, string> = {};
|
|
713
|
+
let confidence = 0.6;
|
|
714
|
+
if (smart) {
|
|
715
|
+
const evidence = findCorroboration(content, corroboration);
|
|
716
|
+
const verdict = verdicts?.get(index);
|
|
717
|
+
const trust = computeTrustScore({
|
|
718
|
+
extractionConfidence: undefined,
|
|
719
|
+
sourceTrust: settings.sourceTrust * NATIVE_TRUST_FACTOR,
|
|
720
|
+
judgeVerdict: verdict,
|
|
721
|
+
evidence,
|
|
722
|
+
});
|
|
723
|
+
const decision = decideSmart(trust, verdict, settings);
|
|
724
|
+
if (decision.outcome === "drop") {
|
|
725
|
+
// Deliberately NOT recorded in importedIds: a dropped native
|
|
726
|
+
// fact re-fetches and re-scores on later syncs, so corpus or
|
|
727
|
+
// corroboration support that arrives later can still admit it.
|
|
728
|
+
// The judge verdict cache keeps repeated rejections cheap
|
|
729
|
+
// (Cursor review on PR #1462).
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
status = decision.outcome === "active" ? "active" : "pending_review";
|
|
733
|
+
confidence = trust;
|
|
734
|
+
trustAttributes = {
|
|
735
|
+
trustScore: trust.toFixed(3),
|
|
736
|
+
trustDecision: decision.reason,
|
|
737
|
+
...(verdict !== undefined ? { judgeVerdict: verdict } : {}),
|
|
738
|
+
...(evidence.corroboratedBySources.length > 0
|
|
739
|
+
? { corroboratedBySources: evidence.corroboratedBySources.join(",") }
|
|
740
|
+
: {}),
|
|
741
|
+
...(evidence.supportingMemoryId !== undefined
|
|
742
|
+
? { supportingMemoryId: evidence.supportingMemoryId }
|
|
743
|
+
: {}),
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
await deps.writer.writeMemory("fact", content, {
|
|
747
|
+
confidence,
|
|
391
748
|
tags: [
|
|
392
749
|
...new Set([
|
|
393
750
|
...(memory.tags ?? []),
|
|
@@ -402,12 +759,13 @@ export async function importNativeMemories(
|
|
|
402
759
|
structuredAttributes: {
|
|
403
760
|
wearableSource: sourceId,
|
|
404
761
|
wearableNativeId: memory.id,
|
|
762
|
+
...trustAttributes,
|
|
405
763
|
},
|
|
406
764
|
contentHashSource: content,
|
|
407
|
-
status
|
|
765
|
+
status,
|
|
408
766
|
});
|
|
409
767
|
imported += 1;
|
|
410
768
|
importedIds.push(memory.id);
|
|
411
769
|
}
|
|
412
|
-
return { imported, importedIds };
|
|
770
|
+
return { imported, importedIds, warnings };
|
|
413
771
|
}
|