@remnic/core 9.3.705 → 9.3.706
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-boundary.d.ts +5 -5
- package/dist/access-boundary.js +10 -10
- package/dist/access-cli.js +26 -25
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +5 -5
- package/dist/access-http.js +14 -14
- package/dist/access-mcp.d.ts +5 -5
- package/dist/access-mcp.js +13 -13
- package/dist/access-operations-batch.js +11 -11
- package/dist/access-operations.d.ts +5 -5
- package/dist/access-operations.js +12 -12
- package/dist/{access-service-C8hc8N2i.d.ts → access-service-j1c1gptF.d.ts} +3 -3
- package/dist/access-service.d.ts +5 -5
- package/dist/access-service.js +9 -9
- package/dist/access-surface-catalog.d.ts +5 -5
- 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/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +4 -4
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +5 -5
- 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/capabilities.d.ts +1 -1
- package/dist/{catalog-CAeU0e1C.d.ts → catalog-CKxilpzS.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +6 -6
- package/dist/{chunk-JZCKDTAS.js → chunk-24FGNOQS.js} +3 -3
- package/dist/{chunk-C2EHWNP2.js → chunk-2VQYHHWB.js} +9 -3
- package/dist/chunk-2VQYHHWB.js.map +1 -0
- package/dist/{chunk-47LPHBIP.js → chunk-3PTOZJOI.js} +2 -2
- package/dist/{chunk-2SYPOX45.js → chunk-4DZATVK5.js} +3 -3
- package/dist/{chunk-S5APSA3U.js → chunk-4E2QCH46.js} +2 -2
- package/dist/{chunk-KKK7YTYN.js → chunk-5GSUBCZM.js} +6 -2
- package/dist/chunk-5GSUBCZM.js.map +1 -0
- package/dist/{chunk-5DTWZ66X.js → chunk-66TSLESZ.js} +2 -2
- package/dist/{chunk-IREVVFTM.js → chunk-6CIAGZ6X.js} +9 -1
- package/dist/chunk-6CIAGZ6X.js.map +1 -0
- package/dist/{chunk-Y4PMATX2.js → chunk-6HPJMR5I.js} +2 -2
- package/dist/{chunk-M5MWSG4S.js → chunk-BGAHTI4C.js} +5 -5
- package/dist/{chunk-OM6ETLLH.js → chunk-C63MK3WL.js} +2 -2
- package/dist/{chunk-GT4VBKM4.js → chunk-EJDAXR7O.js} +5 -5
- package/dist/{chunk-ULVM34NP.js → chunk-ESMY4RJ4.js} +2 -2
- package/dist/{chunk-MNH2OODZ.js → chunk-GKI6LX5L.js} +2 -2
- package/dist/{chunk-KZMMAVR2.js → chunk-HIV5E57C.js} +2 -2
- package/dist/{chunk-SFOAQQDJ.js → chunk-IONFO7UK.js} +3 -3
- package/dist/{chunk-BMKGG7GC.js → chunk-IVCQW4C4.js} +2 -2
- package/dist/chunk-M7R5R6OJ.js +355 -0
- package/dist/chunk-M7R5R6OJ.js.map +1 -0
- package/dist/{chunk-IX3UQT4H.js → chunk-MLLTU5FX.js} +1 -1
- package/dist/chunk-MLLTU5FX.js.map +1 -0
- package/dist/{chunk-NFGJBEPT.js → chunk-MRX6ZXHZ.js} +2 -2
- package/dist/{chunk-GI3MTYDU.js → chunk-N75N5SNX.js} +3 -3
- package/dist/{chunk-BKBSE3BU.js → chunk-NM6TSEGQ.js} +2 -2
- package/dist/{chunk-S3WYRPSA.js → chunk-PDJQVAGM.js} +68 -31
- package/dist/chunk-PDJQVAGM.js.map +1 -0
- package/dist/{chunk-SY6WG6DB.js → chunk-RH2OSRQY.js} +2 -2
- package/dist/{chunk-YTMDF6S7.js → chunk-SPETAWFE.js} +2 -2
- package/dist/{chunk-JHAYR2JY.js → chunk-STYMKPFT.js} +7 -7
- package/dist/{chunk-OMNTQPZO.js → chunk-TKZ3AL5V.js} +2 -2
- package/dist/{chunk-IFR23TC5.js → chunk-VYZNWH4J.js} +37 -6
- package/dist/chunk-VYZNWH4J.js.map +1 -0
- package/dist/{chunk-KFU2SKDD.js → chunk-W2S3Z5MT.js} +2 -2
- package/dist/{chunk-6GJ2WQRK.js → chunk-W2WQ4LE7.js} +2 -2
- package/dist/{chunk-7ARKLLCV.js → chunk-WDH3KUZU.js} +2 -2
- package/dist/{chunk-7L54YZUI.js → chunk-WQADZ3ZY.js} +17 -17
- package/dist/{chunk-HEHPVBWA.js → chunk-WSWYIKXX.js} +4 -4
- package/dist/{chunk-WN4GHSDH.js → chunk-XKMDDM7P.js} +2 -2
- package/dist/{chunk-LY4FJLPT.js → chunk-Y6YHAGQP.js} +2 -2
- package/dist/{cli-ChE0XlJY.d.ts → cli-CbT-pyM4.d.ts} +3 -3
- package/dist/cli.d.ts +6 -6
- package/dist/cli.js +26 -26
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +5 -5
- 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/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +5 -5
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +5 -5
- 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 +5 -5
- package/dist/entity-schema.d.ts +1 -1
- package/dist/event-time.d.ts +35 -1
- package/dist/event-time.js +6 -320
- package/dist/event-time.js.map +1 -1
- package/dist/explicit-capture.d.ts +4 -4
- package/dist/extraction-faithfulness.d.ts +1 -1
- 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.d.ts +10 -1
- package/dist/extraction.js +2 -2
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{forget-6SOIPUMQ.js → forget-U66KPDPY.js} +3 -3
- 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 +35 -34
- 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 +5 -5
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +5 -5
- package/dist/maintenance/rebuild-memory-projection.js +6 -6
- package/dist/mcp-memory-inspector-app.d.ts +5 -5
- 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 +2 -2
- package/dist/namespaces/migrate.js +6 -6
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +5 -5
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +10 -10
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +7 -7
- package/dist/{orchestrator-m_PnhyHj.d.ts → orchestrator-D4ovYV3x.d.ts} +3 -3
- package/dist/orchestrator.d.ts +4 -4
- package/dist/orchestrator.js +20 -19
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.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-explain-renderer.js +3 -3
- package/dist/recall-planner-llm.d.ts +1 -1
- 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-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/resolve-auth-token.d.ts +1 -1
- 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 +38 -0
- package/dist/schemas.js +1 -1
- 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-DVBbq6Wr.d.ts → semantic-consolidation-DyMUCsfN.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +6 -6
- package/dist/semantic-rule-promotion.js +5 -5
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +5 -5
- 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 +5 -1
- package/dist/storage.js +4 -4
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-supersession.js +2 -2
- package/dist/temporal-validity.d.ts +2 -2
- package/dist/temporal-validity.js +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/{types-CJrvHJjx.d.ts → types-Couvz-L3.d.ts} +12 -2
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +5 -5
- package/package.json +2 -2
- package/src/event-time.ts +73 -0
- package/src/extraction-eventtime-wiring.test.ts +269 -0
- package/src/extraction.ts +50 -3
- package/src/orchestrator.ts +71 -17
- package/src/schemas.ts +12 -0
- package/src/storage.ts +13 -2
- package/src/temporal-validity.test.ts +33 -0
- package/src/temporal-validity.ts +24 -1
- package/src/types.ts +12 -2
- package/dist/chunk-C2EHWNP2.js.map +0 -1
- package/dist/chunk-IFR23TC5.js.map +0 -1
- package/dist/chunk-IREVVFTM.js.map +0 -1
- package/dist/chunk-IX3UQT4H.js.map +0 -1
- package/dist/chunk-KKK7YTYN.js.map +0 -1
- package/dist/chunk-S3WYRPSA.js.map +0 -1
- /package/dist/{chunk-JZCKDTAS.js.map → chunk-24FGNOQS.js.map} +0 -0
- /package/dist/{chunk-47LPHBIP.js.map → chunk-3PTOZJOI.js.map} +0 -0
- /package/dist/{chunk-2SYPOX45.js.map → chunk-4DZATVK5.js.map} +0 -0
- /package/dist/{chunk-S5APSA3U.js.map → chunk-4E2QCH46.js.map} +0 -0
- /package/dist/{chunk-5DTWZ66X.js.map → chunk-66TSLESZ.js.map} +0 -0
- /package/dist/{chunk-Y4PMATX2.js.map → chunk-6HPJMR5I.js.map} +0 -0
- /package/dist/{chunk-M5MWSG4S.js.map → chunk-BGAHTI4C.js.map} +0 -0
- /package/dist/{chunk-OM6ETLLH.js.map → chunk-C63MK3WL.js.map} +0 -0
- /package/dist/{chunk-GT4VBKM4.js.map → chunk-EJDAXR7O.js.map} +0 -0
- /package/dist/{chunk-ULVM34NP.js.map → chunk-ESMY4RJ4.js.map} +0 -0
- /package/dist/{chunk-MNH2OODZ.js.map → chunk-GKI6LX5L.js.map} +0 -0
- /package/dist/{chunk-KZMMAVR2.js.map → chunk-HIV5E57C.js.map} +0 -0
- /package/dist/{chunk-SFOAQQDJ.js.map → chunk-IONFO7UK.js.map} +0 -0
- /package/dist/{chunk-BMKGG7GC.js.map → chunk-IVCQW4C4.js.map} +0 -0
- /package/dist/{chunk-NFGJBEPT.js.map → chunk-MRX6ZXHZ.js.map} +0 -0
- /package/dist/{chunk-GI3MTYDU.js.map → chunk-N75N5SNX.js.map} +0 -0
- /package/dist/{chunk-BKBSE3BU.js.map → chunk-NM6TSEGQ.js.map} +0 -0
- /package/dist/{chunk-SY6WG6DB.js.map → chunk-RH2OSRQY.js.map} +0 -0
- /package/dist/{chunk-YTMDF6S7.js.map → chunk-SPETAWFE.js.map} +0 -0
- /package/dist/{chunk-JHAYR2JY.js.map → chunk-STYMKPFT.js.map} +0 -0
- /package/dist/{chunk-OMNTQPZO.js.map → chunk-TKZ3AL5V.js.map} +0 -0
- /package/dist/{chunk-KFU2SKDD.js.map → chunk-W2S3Z5MT.js.map} +0 -0
- /package/dist/{chunk-6GJ2WQRK.js.map → chunk-W2WQ4LE7.js.map} +0 -0
- /package/dist/{chunk-7ARKLLCV.js.map → chunk-WDH3KUZU.js.map} +0 -0
- /package/dist/{chunk-7L54YZUI.js.map → chunk-WQADZ3ZY.js.map} +0 -0
- /package/dist/{chunk-HEHPVBWA.js.map → chunk-WSWYIKXX.js.map} +0 -0
- /package/dist/{chunk-WN4GHSDH.js.map → chunk-XKMDDM7P.js.map} +0 -0
- /package/dist/{chunk-LY4FJLPT.js.map → chunk-Y6YHAGQP.js.map} +0 -0
- /package/dist/{forget-6SOIPUMQ.js.map → forget-U66KPDPY.js.map} +0 -0
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
shouldFilterSupersededFromRecall,
|
|
7
7
|
shouldSupersedeExisting,
|
|
8
8
|
supersessionKeysForFact
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-TKZ3AL5V.js";
|
|
10
|
+
import "./chunk-6CIAGZ6X.js";
|
|
11
11
|
import "./chunk-NU3CSQ4H.js";
|
|
12
12
|
import "./chunk-PZ5AY32C.js";
|
|
13
13
|
export {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { k as MemoryFrontmatter } from './types-
|
|
1
|
+
import { k as MemoryFrontmatter } from './types-Couvz-L3.js';
|
|
2
2
|
import './types-gb_SNtjR.js';
|
|
3
3
|
import './message-parts/index.js';
|
|
4
4
|
|
|
@@ -42,7 +42,7 @@ declare function effectiveInvalidAt(fm: Pick<MemoryFrontmatter, "invalid_at" | "
|
|
|
42
42
|
* the historical filter (CLAUDE.md gotcha #34: distinguish empty from
|
|
43
43
|
* malformed).
|
|
44
44
|
*/
|
|
45
|
-
declare function isValidAsOf(fm: Pick<MemoryFrontmatter, "valid_at" | "invalid_at" | "created" | "supersededAt" | "status">, asOfMs: number): boolean;
|
|
45
|
+
declare function isValidAsOf(fm: Pick<MemoryFrontmatter, "valid_at" | "invalid_at" | "created" | "supersededAt" | "status" | "eventTimeSource">, asOfMs: number): boolean;
|
|
46
46
|
/**
|
|
47
47
|
* Bi-temporal injection filter (issue #1578).
|
|
48
48
|
*
|
package/dist/threading.d.ts
CHANGED
package/dist/tier-migration.d.ts
CHANGED
package/dist/tier-routing.d.ts
CHANGED
package/dist/topics.d.ts
CHANGED
package/dist/transcript.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PluginConfig, T as TranscriptEntry, v as Checkpoint } from './types-
|
|
1
|
+
import { P as PluginConfig, T as TranscriptEntry, v as Checkpoint } from './types-Couvz-L3.js';
|
|
2
2
|
import { SessionIntegrityReport } from './session-integrity.js';
|
|
3
3
|
import './types-gb_SNtjR.js';
|
|
4
4
|
import './message-parts/index.js';
|
|
@@ -1084,8 +1084,9 @@ interface PluginConfig {
|
|
|
1084
1084
|
* Turn on to exclude validity-expired facts from default injection
|
|
1085
1085
|
* candidates (they remain findable by explicit search and `as_of`
|
|
1086
1086
|
* queries). Storage round-trips `observedAt`/`eventTimeSource`; the
|
|
1087
|
-
* extraction prompt
|
|
1088
|
-
*
|
|
1087
|
+
* extraction prompt emits an optional per-fact `eventTime` expression
|
|
1088
|
+
* and `resolveFactEventTime` resolves it against the source turn
|
|
1089
|
+
* timestamp at write time (#1578 PR2).
|
|
1089
1090
|
*/
|
|
1090
1091
|
temporalBiTemporal: boolean;
|
|
1091
1092
|
/**
|
|
@@ -2987,6 +2988,15 @@ interface ExtractedFact {
|
|
|
2987
2988
|
* walked through. Persisted under reasoning-traces/.
|
|
2988
2989
|
*/
|
|
2989
2990
|
reasoningTrace?: ExtractedReasoningTrace;
|
|
2991
|
+
/**
|
|
2992
|
+
* Optional event-time expression for bi-temporal validity (#1578 PR2).
|
|
2993
|
+
* Verbatim temporal anchor extracted from the conversation ("2025-03-01",
|
|
2994
|
+
* "last March", "since 2024", "until 2025-06-01"). Resolved against the
|
|
2995
|
+
* source turn timestamp at write time by `resolveFactEventTime` — never
|
|
2996
|
+
* re-resolved at read. Absent when the fact carries no temporal anchor or
|
|
2997
|
+
* when `temporal.biTemporal` is off.
|
|
2998
|
+
*/
|
|
2999
|
+
eventTime?: string;
|
|
2990
3000
|
}
|
|
2991
3001
|
interface ExtractedReasoningTraceStep {
|
|
2992
3002
|
order: number;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import './types-gb_SNtjR.js';
|
|
2
2
|
import './message-parts/index.js';
|
|
3
|
-
export { au as AccessTrackingEntry, A as ActiveRecallChatType, d as ActiveRecallModelFallbackPolicy, b as ActiveRecallPromptStyle, a as ActiveRecallQueryMode, c as ActiveRecallThinking, J as AgentAccessAuthToken, b8 as AgentAccessHttpConfig, b9 as AgentDefaultsConfig, ba as AgentPersona, f as AgentPersonaModelConfig, bb as BehaviorLoopAdjustment, e as BehaviorLoopPolicyState, bc as BehaviorSignalDirection, B as BehaviorSignalEvent, bd as BehaviorSignalType, aH as BootstrapOptions, aI as BootstrapResult, r as BriefingActiveThread, be as BriefingCalendarSourceError, aU as BriefingConfig, p as BriefingFocus, o as BriefingFollowup, aV as BriefingOpenCommitment, t as BriefingRecentEntity, s as BriefingResult, n as BriefingSections, aW as BriefingWindow, bf as BufferEntryState, ap as BufferState, z as BufferSurpriseEvent, u as BufferTurn, q as CalendarEvent, C as CalendarSource, bg as CaptureMode, v as Checkpoint, bh as CodexCliReasoningEffort, bi as CodexCompactionFlushMode, aX as CodexCompatConfig, bj as CodexConnectorConfig, aG as CodingContext, bk as CodingKnowledgeConfig, aR as CodingModeConfig, bl as CompressionGuidelineActivationState, N as CompressionGuidelineOptimizerActionSummary, K as CompressionGuidelineOptimizerEventCounts, O as CompressionGuidelineOptimizerRuleUpdate, bm as CompressionGuidelineOptimizerSourceWindow, X as CompressionGuidelineOptimizerState, bn as ConfidenceTier, bo as ConsolidationAction, bp as ConsolidationItem, aJ as ConsolidationObservation, a1 as ConsolidationResult, a6 as ContinuityImprovementLoop, a4 as ContinuityIncidentCloseInput, a5 as ContinuityIncidentOpenInput, a3 as ContinuityIncidentRecord, bq as ContinuityIncidentState, br as ContinuityLoopCadence, a7 as ContinuityLoopReviewInput, bs as ContinuityLoopStatus, a8 as ContinuityLoopUpsertInput, bt as ContradictionScanConfig, am as ConversationThread, bu as CronConversationRecallMode, bv as CronRecallMode, aY as DEFAULT_RECALL_DISCLOSURE, a2 as DaySummaryResult, bw as DreamingConfig, bx as DreamingNarrativePromptStyle, by as DreamsDeepSleepConfig, bz as DreamsLightSleepConfig, aP as DreamsPhase, bA as DreamsPhaseStatus, bB as DreamsPhasesConfig, bC as DreamsRemConfig, aQ as DreamsRunResult, aO as DreamsStatusResult, bD as EngramTraceEvent, at as EntityActivityEntry, E as EntityFile, Y as EntityMention, as as EntityRelationship, Z as EntitySchemaDefinition, _ as EntitySchemaSectionDefinition, $ as EntityStructuredSection, aK as EntityTimelineEntry, aZ as ExtractedFact, bE as ExtractedProcedureStep, bF as ExtractedQuestion, bG as ExtractedReasoningTrace, bH as ExtractedReasoningTraceStep, bI as ExtractedRelationship, bJ as ExtractionPassSource, a0 as ExtractionResult, F as FaithfulnessFrontmatter, ar as FileHygieneConfig, G as GatewayConfig, bK as GitHubLiveConnectorConfig, bL as GmailLiveConnectorConfig, bM as GoogleDriveLiveConnectorConfig, bN as HeartbeatConfig, bO as HeartbeatDetectionMode, H as HourlySummary, I as IdentityInjectionMode, y as ImportanceLevel, a9 as ImportanceScore, w as LifecycleState, L as LiveConnectorsConfig, bP as LlmTraceCallback, bQ as LlmTraceEvent, ac as MemoryActionEligibilityContext, a_ as MemoryActionEligibilitySource, W as MemoryActionEvent, bR as MemoryActionOutcome, bS as MemoryActionPolicyDecision, ad as MemoryActionPolicyResult, bT as MemoryActionStatus, U as MemoryActionType, M as MemoryCategory, g as MemoryFile, k as MemoryFrontmatter, aa as MemoryIntent, m as MemoryLifecycleEvent, ae as MemoryLifecycleEventType, af as MemoryLifecycleStateSummary, ao as MemoryLink, bU as MemoryLinkType, a$ as MemoryObservation, bV as MemoryOsPresetName, l as MemoryProjectionCurrentState, b0 as MemoryScope, h as MemoryStatus, av as MemorySummary, aq as MetaState, bW as ModelApi, bX as ModelDefinitionConfig, bY as ModelProviderAuthMode, ag as ModelProviderConfig, bZ as NamespacePolicy, ah as NativeKnowledgeConfig, b_ as NativeKnowledgeFolderRuleConfig, b$ as NativeKnowledgeObsidianVaultConfig, c0 as NativeKnowledgeOpenClawWorkspaceConfig, c1 as NotionLiveConnectorConfig, P as PluginConfig, x as PolicyClass, c2 as PrincipalFromSessionKeyMode, c3 as PrincipalRule, c4 as ProceduralConfig, aj as ProvenanceConfig, ai as ProvenanceSource, ab as QmdSearchExplain, Q as QmdSearchResult, c5 as QuestionEntry, b1 as RECALL_DISCLOSURE_LEVELS, c6 as ReasoningEffort, j as RecallDisclosure, c7 as RecallPipelineConfig, i as RecallPlanMode, c8 as RecallSectionConfig, R as RecallTierExplain, c9 as RecallTraceEvent, ca as RelevanceFeedback, ak as RetrievalTier, cb as SPECULATIVE_TTL_DAYS, cc as ScopeProfileAutoPromoteConfig, aN as ScopeProfileConfig, aL as ScopeProfileLayerId, aM as ScopeProfilePromotionTarget, cd as ScopeProfileTeamProjectConfig, ce as ScopeTeamConfig, cf as ScoredEntity, D as SecretRef, cg as SemanticChunkingConfigShape, S as SessionObserverBandConfig, ch as SignalLevel, al as SignalScanResult, ci as SlotBehaviorConfig, cj as SlotMismatchMode, an as TopicScore, T as TranscriptEntry, ck as TriggerMode, V as VerificationState, cl as confidenceTier, b7 as isRecallDisclosure } from './types-
|
|
3
|
+
export { au as AccessTrackingEntry, A as ActiveRecallChatType, d as ActiveRecallModelFallbackPolicy, b as ActiveRecallPromptStyle, a as ActiveRecallQueryMode, c as ActiveRecallThinking, J as AgentAccessAuthToken, b8 as AgentAccessHttpConfig, b9 as AgentDefaultsConfig, ba as AgentPersona, f as AgentPersonaModelConfig, bb as BehaviorLoopAdjustment, e as BehaviorLoopPolicyState, bc as BehaviorSignalDirection, B as BehaviorSignalEvent, bd as BehaviorSignalType, aH as BootstrapOptions, aI as BootstrapResult, r as BriefingActiveThread, be as BriefingCalendarSourceError, aU as BriefingConfig, p as BriefingFocus, o as BriefingFollowup, aV as BriefingOpenCommitment, t as BriefingRecentEntity, s as BriefingResult, n as BriefingSections, aW as BriefingWindow, bf as BufferEntryState, ap as BufferState, z as BufferSurpriseEvent, u as BufferTurn, q as CalendarEvent, C as CalendarSource, bg as CaptureMode, v as Checkpoint, bh as CodexCliReasoningEffort, bi as CodexCompactionFlushMode, aX as CodexCompatConfig, bj as CodexConnectorConfig, aG as CodingContext, bk as CodingKnowledgeConfig, aR as CodingModeConfig, bl as CompressionGuidelineActivationState, N as CompressionGuidelineOptimizerActionSummary, K as CompressionGuidelineOptimizerEventCounts, O as CompressionGuidelineOptimizerRuleUpdate, bm as CompressionGuidelineOptimizerSourceWindow, X as CompressionGuidelineOptimizerState, bn as ConfidenceTier, bo as ConsolidationAction, bp as ConsolidationItem, aJ as ConsolidationObservation, a1 as ConsolidationResult, a6 as ContinuityImprovementLoop, a4 as ContinuityIncidentCloseInput, a5 as ContinuityIncidentOpenInput, a3 as ContinuityIncidentRecord, bq as ContinuityIncidentState, br as ContinuityLoopCadence, a7 as ContinuityLoopReviewInput, bs as ContinuityLoopStatus, a8 as ContinuityLoopUpsertInput, bt as ContradictionScanConfig, am as ConversationThread, bu as CronConversationRecallMode, bv as CronRecallMode, aY as DEFAULT_RECALL_DISCLOSURE, a2 as DaySummaryResult, bw as DreamingConfig, bx as DreamingNarrativePromptStyle, by as DreamsDeepSleepConfig, bz as DreamsLightSleepConfig, aP as DreamsPhase, bA as DreamsPhaseStatus, bB as DreamsPhasesConfig, bC as DreamsRemConfig, aQ as DreamsRunResult, aO as DreamsStatusResult, bD as EngramTraceEvent, at as EntityActivityEntry, E as EntityFile, Y as EntityMention, as as EntityRelationship, Z as EntitySchemaDefinition, _ as EntitySchemaSectionDefinition, $ as EntityStructuredSection, aK as EntityTimelineEntry, aZ as ExtractedFact, bE as ExtractedProcedureStep, bF as ExtractedQuestion, bG as ExtractedReasoningTrace, bH as ExtractedReasoningTraceStep, bI as ExtractedRelationship, bJ as ExtractionPassSource, a0 as ExtractionResult, F as FaithfulnessFrontmatter, ar as FileHygieneConfig, G as GatewayConfig, bK as GitHubLiveConnectorConfig, bL as GmailLiveConnectorConfig, bM as GoogleDriveLiveConnectorConfig, bN as HeartbeatConfig, bO as HeartbeatDetectionMode, H as HourlySummary, I as IdentityInjectionMode, y as ImportanceLevel, a9 as ImportanceScore, w as LifecycleState, L as LiveConnectorsConfig, bP as LlmTraceCallback, bQ as LlmTraceEvent, ac as MemoryActionEligibilityContext, a_ as MemoryActionEligibilitySource, W as MemoryActionEvent, bR as MemoryActionOutcome, bS as MemoryActionPolicyDecision, ad as MemoryActionPolicyResult, bT as MemoryActionStatus, U as MemoryActionType, M as MemoryCategory, g as MemoryFile, k as MemoryFrontmatter, aa as MemoryIntent, m as MemoryLifecycleEvent, ae as MemoryLifecycleEventType, af as MemoryLifecycleStateSummary, ao as MemoryLink, bU as MemoryLinkType, a$ as MemoryObservation, bV as MemoryOsPresetName, l as MemoryProjectionCurrentState, b0 as MemoryScope, h as MemoryStatus, av as MemorySummary, aq as MetaState, bW as ModelApi, bX as ModelDefinitionConfig, bY as ModelProviderAuthMode, ag as ModelProviderConfig, bZ as NamespacePolicy, ah as NativeKnowledgeConfig, b_ as NativeKnowledgeFolderRuleConfig, b$ as NativeKnowledgeObsidianVaultConfig, c0 as NativeKnowledgeOpenClawWorkspaceConfig, c1 as NotionLiveConnectorConfig, P as PluginConfig, x as PolicyClass, c2 as PrincipalFromSessionKeyMode, c3 as PrincipalRule, c4 as ProceduralConfig, aj as ProvenanceConfig, ai as ProvenanceSource, ab as QmdSearchExplain, Q as QmdSearchResult, c5 as QuestionEntry, b1 as RECALL_DISCLOSURE_LEVELS, c6 as ReasoningEffort, j as RecallDisclosure, c7 as RecallPipelineConfig, i as RecallPlanMode, c8 as RecallSectionConfig, R as RecallTierExplain, c9 as RecallTraceEvent, ca as RelevanceFeedback, ak as RetrievalTier, cb as SPECULATIVE_TTL_DAYS, cc as ScopeProfileAutoPromoteConfig, aN as ScopeProfileConfig, aL as ScopeProfileLayerId, aM as ScopeProfilePromotionTarget, cd as ScopeProfileTeamProjectConfig, ce as ScopeTeamConfig, cf as ScoredEntity, D as SecretRef, cg as SemanticChunkingConfigShape, S as SessionObserverBandConfig, ch as SignalLevel, al as SignalScanResult, ci as SlotBehaviorConfig, cj as SlotMismatchMode, an as TopicScore, T as TranscriptEntry, ck as TriggerMode, V as VerificationState, cl as confidenceTier, b7 as isRecallDisclosure } from './types-Couvz-L3.js';
|
package/dist/types.js
CHANGED
package/dist/verified-recall.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
compareVerifiedEpisodeResults,
|
|
3
3
|
searchVerifiedEpisodes
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MRX6ZXHZ.js";
|
|
5
5
|
import "./chunk-7FL4CNPV.js";
|
|
6
6
|
import "./chunk-ZBJMUXZH.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-2VQYHHWB.js";
|
|
8
8
|
import "./chunk-M7XQSUBB.js";
|
|
9
9
|
import "./chunk-3JJWNZTT.js";
|
|
10
10
|
import "./chunk-5UZXUTVO.js";
|
|
11
11
|
import "./chunk-5GPPACXK.js";
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-TKZ3AL5V.js";
|
|
13
|
+
import "./chunk-6CIAGZ6X.js";
|
|
14
14
|
import "./chunk-SVOZFLIQ.js";
|
|
15
15
|
import "./chunk-LTJAMRGI.js";
|
|
16
16
|
import "./chunk-J6A3CX5N.js";
|
|
17
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-MLLTU5FX.js";
|
|
18
18
|
import "./chunk-RULE4VG5.js";
|
|
19
19
|
import "./chunk-SCU65EZI.js";
|
|
20
20
|
import "./chunk-MB5RSUW6.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/core",
|
|
3
|
-
"version": "9.3.
|
|
3
|
+
"version": "9.3.706",
|
|
4
4
|
"description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -2966,7 +2966,7 @@
|
|
|
2966
2966
|
"core"
|
|
2967
2967
|
],
|
|
2968
2968
|
"peerDependencies": {
|
|
2969
|
-
"@remnic/coding-graph": "^9.3.
|
|
2969
|
+
"@remnic/coding-graph": "^9.3.706"
|
|
2970
2970
|
},
|
|
2971
2971
|
"peerDependenciesMeta": {
|
|
2972
2972
|
"@remnic/coding-graph": {
|
package/src/event-time.ts
CHANGED
|
@@ -286,6 +286,14 @@ function resolveQuarter(
|
|
|
286
286
|
*/
|
|
287
287
|
function resolveAbsolute(raw: string): number | null {
|
|
288
288
|
const trimmed = raw.trim();
|
|
289
|
+
// YYYY-MM (ISO year-month, no day) → first day of that month, UTC
|
|
290
|
+
// (#1578 review r3: the prompt example "until 2025-06" must resolve, not
|
|
291
|
+
// fall back to "assumed").
|
|
292
|
+
const ym = /^(\d{4})-(\d{2})$/.exec(trimmed);
|
|
293
|
+
if (ym) {
|
|
294
|
+
const ms = buildDateMs(Number(ym[1]), Number(ym[2]), 1);
|
|
295
|
+
return ms === null ? null : startOfDayUtc(ms);
|
|
296
|
+
}
|
|
289
297
|
const ms = parseFlexibleIsoTimestamp(trimmed);
|
|
290
298
|
if (ms === null) return null;
|
|
291
299
|
// Date-only inputs (no T) anchor to start-of-day UTC.
|
|
@@ -469,6 +477,17 @@ function resolveEndBound(anchorMs: number, period: string): number | null {
|
|
|
469
477
|
return buildDateMs(Number(trimmed) + 1, 1, 1);
|
|
470
478
|
}
|
|
471
479
|
|
|
480
|
+
// YYYY-MM (year-month) end bound: exclusive end = start of the FOLLOWING
|
|
481
|
+
// month, so "until 2025-06" spans all of June (#1578 review r3).
|
|
482
|
+
const ymEnd = /^(\d{4})-(\d{2})$/.exec(trimmed);
|
|
483
|
+
if (ymEnd) {
|
|
484
|
+
const startMs = buildDateMs(Number(ymEnd[1]), Number(ymEnd[2]), 1);
|
|
485
|
+
if (startMs === null) return null;
|
|
486
|
+
const nd = new Date(startMs);
|
|
487
|
+
nd.setUTCMonth(nd.getUTCMonth() + 1);
|
|
488
|
+
return startOfDayUtc(nd.getTime());
|
|
489
|
+
}
|
|
490
|
+
|
|
472
491
|
// Absolute date/datetime end bound.
|
|
473
492
|
const absMs = resolveAbsolute(trimmed);
|
|
474
493
|
if (absMs !== null) {
|
|
@@ -546,3 +565,57 @@ function resolveEndBound(anchorMs: number, period: string): number | null {
|
|
|
546
565
|
}
|
|
547
566
|
return null;
|
|
548
567
|
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Resolved bi-temporal fields for a single extracted fact (issue #1578 PR2).
|
|
571
|
+
*
|
|
572
|
+
* - `validFrom` / `validUntil` — the event-time `[from, until)` interval.
|
|
573
|
+
* When `eventTimeSource === "assumed"`, `validFrom` is copied from
|
|
574
|
+
* `observedAt` (the ingestion anchor) so every bi-temporal-on fact carries
|
|
575
|
+
* at least a start bound.
|
|
576
|
+
* - `observedAt` — always the ingestion anchor (the source turn timestamp).
|
|
577
|
+
* - `eventTimeSource` — `"extracted"` when the expression resolved to a real
|
|
578
|
+
* event-time interval; `"assumed"` when the expression was absent or
|
|
579
|
+
* unresolvable.
|
|
580
|
+
*
|
|
581
|
+
* This is the single write-time helper every extraction entry path calls
|
|
582
|
+
* (rule 39). It is pure: (expression, anchor) in, interval out. Resolution
|
|
583
|
+
* never touches `Date.now()` — replay/import of old transcripts resolves
|
|
584
|
+
* against the old anchor.
|
|
585
|
+
*/
|
|
586
|
+
export interface FactEventTime {
|
|
587
|
+
validFrom?: string;
|
|
588
|
+
validUntil?: string;
|
|
589
|
+
observedAt: string;
|
|
590
|
+
eventTimeSource: "extracted" | "assumed";
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Resolve a single fact's event-time expression against the ingestion anchor.
|
|
595
|
+
*
|
|
596
|
+
* Returns the bi-temporal interval to persist alongside the fact. When the
|
|
597
|
+
* expression is absent, empty, or unresolvable, falls back to
|
|
598
|
+
* `eventTimeSource: "assumed"` with `validFrom = observedAt` — per the
|
|
599
|
+
* #1578 frontmatter contract. When the expression resolves but only pins one
|
|
600
|
+
* bound ("since 2024" → validFrom only; "until 2025-06" → validUntil only),
|
|
601
|
+
* only the resolved bound is returned.
|
|
602
|
+
*/
|
|
603
|
+
export function resolveFactEventTime(
|
|
604
|
+
expression: string | undefined | null,
|
|
605
|
+
anchorIso: string,
|
|
606
|
+
): FactEventTime {
|
|
607
|
+
const resolved = resolveEventTime(expression, anchorIso);
|
|
608
|
+
if (resolved.ok && (resolved.validFrom !== undefined || resolved.validUntil !== undefined)) {
|
|
609
|
+
return {
|
|
610
|
+
...(resolved.validFrom !== undefined ? { validFrom: resolved.validFrom } : {}),
|
|
611
|
+
...(resolved.validUntil !== undefined ? { validUntil: resolved.validUntil } : {}),
|
|
612
|
+
observedAt: anchorIso,
|
|
613
|
+
eventTimeSource: "extracted",
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
return {
|
|
617
|
+
validFrom: anchorIso,
|
|
618
|
+
observedAt: anchorIso,
|
|
619
|
+
eventTimeSource: "assumed",
|
|
620
|
+
};
|
|
621
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
6
|
+
|
|
7
|
+
import { resolveFactEventTime } from "./event-time.js";
|
|
8
|
+
import { ExtractionEngine } from "./extraction.js";
|
|
9
|
+
import { ExtractedFactSchema } from "./schemas.js";
|
|
10
|
+
import { StorageManager } from "./storage.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Issue #1578 PR 2 — extraction event-time wiring.
|
|
14
|
+
*
|
|
15
|
+
* Proves three contracts:
|
|
16
|
+
* 1. resolveFactEventTime anchors to the SOURCE TURN timestamp, never
|
|
17
|
+
* wall-clock — replay/import of an old transcript yields old-era event
|
|
18
|
+
* times (the core bi-temporal invariant from the #1578 design).
|
|
19
|
+
* 2. Extraction normalization passes the per-fact `eventTime` expression
|
|
20
|
+
* through from raw LLM JSON (camelCase and snake_case payloads) so the
|
|
21
|
+
* persist path can resolve it at write time.
|
|
22
|
+
* 3. Storage round-trips `invalid_at` so the bi-temporal interval survives
|
|
23
|
+
* write → read (complementing PR 1's observedAt/eventTimeSource test).
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
// ── 1. Replay anchoring ──────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
test("resolveFactEventTime: replay of a 2025 transcript anchors 'last March' to 2025-03, not today", () => {
|
|
29
|
+
// The anchor is the source turn timestamp from an old (2025) transcript.
|
|
30
|
+
const anchor2025 = "2025-04-10T12:00:00.000Z";
|
|
31
|
+
const result = resolveFactEventTime("last March", anchor2025);
|
|
32
|
+
assert.equal(result.eventTimeSource, "extracted");
|
|
33
|
+
assert.ok(result.validFrom, "validFrom must be set for a resolvable expression");
|
|
34
|
+
// "last March" relative to April 2025 → March 2025.
|
|
35
|
+
assert.ok(result.validFrom!.startsWith("2025-03"), `expected 2025-03, got ${result.validFrom}`);
|
|
36
|
+
// Critical bi-temporal invariant: NOT anchored to today's wall-clock.
|
|
37
|
+
assert.ok(!result.validFrom!.startsWith("2026"), "must not anchor to wall-clock");
|
|
38
|
+
assert.equal(result.observedAt, anchor2025);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("resolveFactEventTime: same expression, different anchors → different validFrom", () => {
|
|
42
|
+
// The identical phrase resolves differently depending on the anchor —
|
|
43
|
+
// proving the resolver is anchor-driven, not Date.now()-driven.
|
|
44
|
+
const old = resolveFactEventTime("yesterday", "2025-01-15T10:00:00.000Z");
|
|
45
|
+
const recent = resolveFactEventTime("yesterday", "2026-07-05T10:00:00.000Z");
|
|
46
|
+
assert.ok(old.validFrom!.startsWith("2025-01-14"), `got ${old.validFrom}`);
|
|
47
|
+
assert.ok(recent.validFrom!.startsWith("2026-07-04"), `got ${recent.validFrom}`);
|
|
48
|
+
assert.notEqual(old.validFrom, recent.validFrom);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("resolveFactEventTime: absent expression → 'assumed' with validFrom = anchor", () => {
|
|
52
|
+
const anchor = "2025-06-01T00:00:00.000Z";
|
|
53
|
+
const result = resolveFactEventTime(undefined, anchor);
|
|
54
|
+
assert.equal(result.eventTimeSource, "assumed");
|
|
55
|
+
assert.equal(result.validFrom, anchor);
|
|
56
|
+
assert.equal(result.observedAt, anchor);
|
|
57
|
+
assert.equal(result.validUntil, undefined);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("resolveFactEventTime: 'since 2024' → validFrom only (open-ended start)", () => {
|
|
61
|
+
const result = resolveFactEventTime("since 2024", "2025-06-01T00:00:00.000Z");
|
|
62
|
+
assert.equal(result.eventTimeSource, "extracted");
|
|
63
|
+
assert.ok(result.validFrom!.startsWith("2024-01-01"));
|
|
64
|
+
assert.equal(result.validUntil, undefined);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("resolveFactEventTime: unresolvable garbage → 'assumed' fallback", () => {
|
|
68
|
+
const anchor = "2025-06-01T00:00:00.000Z";
|
|
69
|
+
const result = resolveFactEventTime("sometime maybe???", anchor);
|
|
70
|
+
assert.equal(result.eventTimeSource, "assumed");
|
|
71
|
+
assert.equal(result.validFrom, anchor);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// ── 2. Extraction normalization passes eventTime through ─────────────────
|
|
75
|
+
|
|
76
|
+
function makeEngine(): ExtractionEngine {
|
|
77
|
+
// Minimal construction: the facts normalizer is a pure data transform
|
|
78
|
+
// (no LLM / I/O). Stub the optional deps so the constructor doesn't
|
|
79
|
+
// spin up real clients.
|
|
80
|
+
return new ExtractionEngine(
|
|
81
|
+
{ memoryDir: "/tmp" } as any,
|
|
82
|
+
undefined, // profiler → safe default
|
|
83
|
+
{} as any, // localLlm stub
|
|
84
|
+
undefined, // gatewayConfig
|
|
85
|
+
{} as any, // modelRegistry stub
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
test("extraction normalization: camelCase 'eventTime' passes through to ExtractedFact", () => {
|
|
90
|
+
const engine = makeEngine();
|
|
91
|
+
const result = (engine as any).normalizeExtractionResultPayload({
|
|
92
|
+
facts: [
|
|
93
|
+
{ content: "We moved offices in March.", category: "fact", eventTime: "last March" },
|
|
94
|
+
],
|
|
95
|
+
entities: [],
|
|
96
|
+
});
|
|
97
|
+
assert.equal(result.facts.length, 1);
|
|
98
|
+
assert.equal(result.facts[0].eventTime, "last March");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("extraction normalization: snake_case 'event_time' also captured", () => {
|
|
102
|
+
const engine = makeEngine();
|
|
103
|
+
const result = (engine as any).normalizeExtractionResultPayload({
|
|
104
|
+
facts: [
|
|
105
|
+
{ content: "Switched to PostgreSQL.", category: "fact", event_time: "2025-01-15" },
|
|
106
|
+
],
|
|
107
|
+
entities: [],
|
|
108
|
+
});
|
|
109
|
+
assert.equal(result.facts[0].eventTime, "2025-01-15");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("extraction normalization: absent eventTime → undefined (assumed deferred to write time)", () => {
|
|
113
|
+
const engine = makeEngine();
|
|
114
|
+
const result = (engine as any).normalizeExtractionResultPayload({
|
|
115
|
+
facts: [{ content: "The sky is blue.", category: "fact" }],
|
|
116
|
+
entities: [],
|
|
117
|
+
});
|
|
118
|
+
assert.equal(result.facts[0].eventTime, undefined);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// ── 2b. Schema preserves snake_case event_time (gateway fix, chatgpt-codex) ─
|
|
122
|
+
|
|
123
|
+
test("ExtractedFactSchema: snake_case event_time survives schema parse (gateway strip-unknown fix)", () => {
|
|
124
|
+
// Zod .object() strips unknown keys by default. Before the event_time alias
|
|
125
|
+
// was added, the gateway fallback path (parseWithSchemaDetailed → schema.parse)
|
|
126
|
+
// silently dropped event_time, losing the temporal bound (#1578).
|
|
127
|
+
const parsed = ExtractedFactSchema.parse({
|
|
128
|
+
content: "Switched to PostgreSQL.",
|
|
129
|
+
category: "fact",
|
|
130
|
+
confidence: 0.9,
|
|
131
|
+
tags: [],
|
|
132
|
+
event_time: "2025-01-15",
|
|
133
|
+
});
|
|
134
|
+
assert.equal(parsed.event_time, "2025-01-15");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("ExtractedFactSchema: camelCase eventTime also survives schema parse (no regression)", () => {
|
|
138
|
+
const parsed = ExtractedFactSchema.parse({
|
|
139
|
+
content: "We moved offices in March.",
|
|
140
|
+
category: "fact",
|
|
141
|
+
confidence: 0.8,
|
|
142
|
+
tags: [],
|
|
143
|
+
eventTime: "2025-03",
|
|
144
|
+
});
|
|
145
|
+
assert.equal(parsed.eventTime, "2025-03");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// ── 3. Storage round-trips invalid_at ────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
test("storage: invalid_at round-trips through writeMemoryFrontmatter → readAllMemories", async () => {
|
|
151
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-et-invalidAt-"));
|
|
152
|
+
try {
|
|
153
|
+
const storage = new StorageManager(dir);
|
|
154
|
+
await storage.ensureDirectories();
|
|
155
|
+
|
|
156
|
+
const id = await storage.writeMemory("fact", "Old stack was Node 18.", {
|
|
157
|
+
validAt: "2025-01-01T00:00:00.000Z",
|
|
158
|
+
observedAt: "2025-06-01T00:00:00.000Z",
|
|
159
|
+
eventTimeSource: "extracted",
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const before = await storage.readAllMemories();
|
|
163
|
+
const mem = before.find((m) => m.frontmatter.id === id);
|
|
164
|
+
assert.ok(mem);
|
|
165
|
+
|
|
166
|
+
const ok = await storage.writeMemoryFrontmatter(mem!, {
|
|
167
|
+
invalid_at: "2025-06-15T00:00:00.000Z",
|
|
168
|
+
});
|
|
169
|
+
assert.equal(ok, true);
|
|
170
|
+
|
|
171
|
+
const after = await storage.readAllMemories();
|
|
172
|
+
const patched = after.find((m) => m.frontmatter.id === id);
|
|
173
|
+
assert.ok(patched, "patched fact must be readable");
|
|
174
|
+
assert.equal(patched!.frontmatter.invalid_at, "2025-06-15T00:00:00.000Z");
|
|
175
|
+
// Bi-temporal provenance preserved through the frontmatter patch.
|
|
176
|
+
assert.equal(patched!.frontmatter.observedAt, "2025-06-01T00:00:00.000Z");
|
|
177
|
+
assert.equal(patched!.frontmatter.eventTimeSource, "extracted");
|
|
178
|
+
assert.equal(patched!.frontmatter.valid_at, "2025-01-01T00:00:00.000Z");
|
|
179
|
+
} finally {
|
|
180
|
+
await rm(dir, { recursive: true, force: true });
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("storage: writeMemory accepts invalidAt directly (end-bound at extraction write time)", async () => {
|
|
185
|
+
// Proves Fix C: writeMemory now accepts invalidAt so "until X" expressions
|
|
186
|
+
// persist invalid_at at write time without a separate updateMemoryFrontmatter call.
|
|
187
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-et-writeMem-invalid-"));
|
|
188
|
+
try {
|
|
189
|
+
const storage = new StorageManager(dir);
|
|
190
|
+
await storage.ensureDirectories();
|
|
191
|
+
const id = await storage.writeMemory("fact", "We used MongoDB until June 2025.", {
|
|
192
|
+
validAt: "2024-01-01T00:00:00.000Z",
|
|
193
|
+
invalidAt: "2025-06-01T00:00:00.000Z",
|
|
194
|
+
observedAt: "2025-06-20T00:00:00.000Z",
|
|
195
|
+
eventTimeSource: "extracted",
|
|
196
|
+
});
|
|
197
|
+
const mems = await storage.readAllMemories();
|
|
198
|
+
const mem = mems.find((m) => m.frontmatter.id === id);
|
|
199
|
+
assert.ok(mem);
|
|
200
|
+
assert.equal(mem!.frontmatter.valid_at, "2024-01-01T00:00:00.000Z");
|
|
201
|
+
assert.equal(mem!.frontmatter.invalid_at, "2025-06-01T00:00:00.000Z");
|
|
202
|
+
assert.equal(mem!.frontmatter.observedAt, "2025-06-20T00:00:00.000Z");
|
|
203
|
+
assert.equal(mem!.frontmatter.eventTimeSource, "extracted");
|
|
204
|
+
} finally {
|
|
205
|
+
await rm(dir, { recursive: true, force: true });
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("resolveFactEventTime: 'through 2026' → validUntil only (open-ended end bound)", () => {
|
|
210
|
+
const result = resolveFactEventTime("through 2026", "2025-06-20T00:00:00.000Z");
|
|
211
|
+
assert.equal(result.eventTimeSource, "extracted");
|
|
212
|
+
assert.equal(result.validFrom, undefined);
|
|
213
|
+
assert.ok(result.validUntil, "validUntil must be set for an end-bound expression");
|
|
214
|
+
// "through 2026" → exclusive end = start of 2027.
|
|
215
|
+
assert.equal(result.validUntil, "2027-01-01T00:00:00.000Z");
|
|
216
|
+
});
|
|
217
|
+
test("storage: writeChunk propagates invalidAt/observedAt/eventTimeSource from the parent fact (#1578 PR2)", async () => {
|
|
218
|
+
// Proves the cursor-bugbot fix: an independently-surfaced chunk expires at the
|
|
219
|
+
// same invalid_at window as its parent so recall's isValidityExpiredNow check
|
|
220
|
+
// fires on chunks too, not just the chunked parent write.
|
|
221
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-et-chunk-invalid-"));
|
|
222
|
+
try {
|
|
223
|
+
const storage = new StorageManager(dir);
|
|
224
|
+
await storage.ensureDirectories();
|
|
225
|
+
const parentId = await storage.writeMemory("fact", "We used MongoDB until June 2025.", {
|
|
226
|
+
validAt: "2024-01-01T00:00:00.000Z",
|
|
227
|
+
invalidAt: "2025-06-01T00:00:00.000Z",
|
|
228
|
+
observedAt: "2025-06-20T00:00:00.000Z",
|
|
229
|
+
eventTimeSource: "extracted",
|
|
230
|
+
});
|
|
231
|
+
const chunkId = await storage.writeChunk(
|
|
232
|
+
parentId,
|
|
233
|
+
0,
|
|
234
|
+
1,
|
|
235
|
+
"fact",
|
|
236
|
+
"We used MongoDB until June 2025.",
|
|
237
|
+
{
|
|
238
|
+
validAt: "2024-01-01T00:00:00.000Z",
|
|
239
|
+
invalidAt: "2025-06-01T00:00:00.000Z",
|
|
240
|
+
observedAt: "2025-06-20T00:00:00.000Z",
|
|
241
|
+
eventTimeSource: "extracted",
|
|
242
|
+
},
|
|
243
|
+
);
|
|
244
|
+
const mems = await storage.readAllMemories();
|
|
245
|
+
const chunk = mems.find((m) => m.frontmatter.id === chunkId);
|
|
246
|
+
assert.ok(chunk, "chunk must be readable");
|
|
247
|
+
assert.equal(chunk!.frontmatter.valid_at, "2024-01-01T00:00:00.000Z");
|
|
248
|
+
assert.equal(chunk!.frontmatter.invalid_at, "2025-06-01T00:00:00.000Z",
|
|
249
|
+
"chunk must carry the parent's end bound so it expires independently");
|
|
250
|
+
assert.equal(chunk!.frontmatter.observedAt, "2025-06-20T00:00:00.000Z");
|
|
251
|
+
assert.equal(chunk!.frontmatter.eventTimeSource, "extracted");
|
|
252
|
+
} finally {
|
|
253
|
+
await rm(dir, { recursive: true, force: true });
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
test("resolveFactEventTime: 'until 2025-06' (YYYY-MM) → invalidAt = start of following month (#1578 r3)", () => {
|
|
257
|
+
const result = resolveFactEventTime("until 2025-06", "2025-06-20T00:00:00.000Z");
|
|
258
|
+
assert.equal(result.eventTimeSource, "extracted");
|
|
259
|
+
assert.equal(result.validFrom, undefined);
|
|
260
|
+
assert.equal(result.validUntil, "2025-07-01T00:00:00.000Z",
|
|
261
|
+
"YYYY-MM end bound must span the whole month, not fall back to assumed");
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test("resolveFactEventTime: bare '2025-03' (YYYY-MM) → validFrom = first of month (#1578 r3)", () => {
|
|
265
|
+
const result = resolveFactEventTime("2025-03", "2025-06-20T00:00:00.000Z");
|
|
266
|
+
assert.equal(result.eventTimeSource, "extracted");
|
|
267
|
+
assert.equal(result.validFrom, "2025-03-01T00:00:00.000Z");
|
|
268
|
+
assert.equal(result.validUntil, undefined);
|
|
269
|
+
});
|
package/src/extraction.ts
CHANGED
|
@@ -279,6 +279,12 @@ export class ExtractionEngine {
|
|
|
279
279
|
typeof f?.quote === "string" && f.quote.trim().length > 0
|
|
280
280
|
? f.quote
|
|
281
281
|
: undefined,
|
|
282
|
+
eventTime:
|
|
283
|
+
typeof f?.eventTime === "string" && f.eventTime.trim().length > 0
|
|
284
|
+
? f.eventTime.trim()
|
|
285
|
+
: typeof f?.event_time === "string" && f.event_time.trim().length > 0
|
|
286
|
+
? f.event_time.trim()
|
|
287
|
+
: undefined,
|
|
282
288
|
}))
|
|
283
289
|
.filter((f: any) => f.content.length > 0)
|
|
284
290
|
: [];
|
|
@@ -750,6 +756,11 @@ export class ExtractionEngine {
|
|
|
750
756
|
this.config.provenance?.enabled
|
|
751
757
|
? '- Source quotes: For each fact, include a "quote" field with the EXACT verbatim words from the conversation that support the fact (a contiguous span from a single turn, not a paraphrase). Cap at ~300 chars.'
|
|
752
758
|
: "",
|
|
759
|
+
// #1578: emit the same event-time guidance as the primary extraction
|
|
760
|
+
// paths so proactive-recovered facts also carry an optional eventTime
|
|
761
|
+
// (chatgpt-codex thread on extraction.ts:1607). Returns "" when the
|
|
762
|
+
// bi-temporal gate is off, keeping the prompt unchanged by default.
|
|
763
|
+
this.eventTimePromptInstruction(),
|
|
753
764
|
"",
|
|
754
765
|
"Base extracted facts (do not repeat):",
|
|
755
766
|
factsPreview || "(none)",
|
|
@@ -1250,10 +1261,23 @@ export class ExtractionEngine {
|
|
|
1250
1261
|
// reasoningTrace through normalizeReasoningTrace before passing it on so
|
|
1251
1262
|
// gateway output matches the shape local/direct-client paths produce.
|
|
1252
1263
|
const normalizedFacts = result.facts.map((f: any) => {
|
|
1253
|
-
if (!f
|
|
1264
|
+
if (!f) return f;
|
|
1265
|
+
// Gateway tolerance: collapse snake_case event_time → camelCase
|
|
1266
|
+
// eventTime so the gateway path matches the local/direct/proactive
|
|
1267
|
+
// normalization (#1578 r3 — cursor bugbot).
|
|
1268
|
+
const eventTime =
|
|
1269
|
+
typeof f.eventTime === "string" && f.eventTime.trim().length > 0
|
|
1270
|
+
? f.eventTime.trim()
|
|
1271
|
+
: typeof f.event_time === "string" && f.event_time.trim().length > 0
|
|
1272
|
+
? f.event_time.trim()
|
|
1273
|
+
: undefined;
|
|
1274
|
+
if (!f.reasoningTrace && eventTime === undefined) return f;
|
|
1254
1275
|
return {
|
|
1255
1276
|
...f,
|
|
1256
|
-
|
|
1277
|
+
...(f.reasoningTrace
|
|
1278
|
+
? { reasoningTrace: normalizeReasoningTrace(f.reasoningTrace) ?? undefined }
|
|
1279
|
+
: {}),
|
|
1280
|
+
...(eventTime !== undefined ? { eventTime } : {}),
|
|
1257
1281
|
};
|
|
1258
1282
|
});
|
|
1259
1283
|
const sanitized = this.sanitizeExtractionResult({
|
|
@@ -1394,7 +1418,7 @@ Examples of when to add structuredAttributes:
|
|
|
1394
1418
|
- Decisions: {"chosen": "PostgreSQL", "rejected": "MongoDB", "reason": "ACID compliance"}
|
|
1395
1419
|
- Quantities/measurements: {"budget": "50000", "team_size": "5", "deadline": "2024-06-01"}
|
|
1396
1420
|
Only add structuredAttributes when there are concrete values. Skip for abstract or narrative facts.
|
|
1397
|
-
|
|
1421
|
+
${this.eventTimePromptInstruction()}
|
|
1398
1422
|
Also generate:
|
|
1399
1423
|
1. 1-3 genuine questions you're curious about from this conversation
|
|
1400
1424
|
2. Profile updates about user patterns/behaviors (if any)
|
|
@@ -1595,6 +1619,28 @@ ${truncatedConversation}`;
|
|
|
1595
1619
|
return { facts, entities, profileUpdates: [], questions: [] };
|
|
1596
1620
|
}
|
|
1597
1621
|
|
|
1622
|
+
/**
|
|
1623
|
+
* Bi-temporal event-time extraction instruction (#1578 PR2). Emitted on
|
|
1624
|
+
* every extraction entry path when `temporal.biTemporal` is on so the LLM
|
|
1625
|
+
* emits an optional per-fact `eventTime` expression. The expression is
|
|
1626
|
+
* resolved against the source turn timestamp at write time — never
|
|
1627
|
+
* wall-clock — so replay/import of old transcripts anchors correctly.
|
|
1628
|
+
* Returns an empty string when the gate is off (byte-identical prompt).
|
|
1629
|
+
*/
|
|
1630
|
+
private eventTimePromptInstruction(): string {
|
|
1631
|
+
if (!this.config.temporalBiTemporal) return "";
|
|
1632
|
+
return `
|
|
1633
|
+
=== Event Time (bi-temporal) ===
|
|
1634
|
+
When a fact has an explicit temporal anchor — a date, month, season, or relative time expression stating WHEN the fact became (or stopped being) true — capture it verbatim in an "eventTime" field on that fact. Examples:
|
|
1635
|
+
- "We moved offices in March" → "eventTime": "last March"
|
|
1636
|
+
- "The API has been rate-limited since 2024" → "eventTime": "since 2024"
|
|
1637
|
+
- "I switched to PostgreSQL on 2025-01-15" → "eventTime": "2025-01-15"
|
|
1638
|
+
- "We used MongoDB until June 2025" → "eventTime": "until 2025-06"
|
|
1639
|
+
Accepted forms: ISO dates ("2025-03-01"), year-month ("2025-03"), month/season + year ("March 2025", "summer 2024"), relative ("yesterday", "last week", "this month", "next year", "last December"), and open-ended ("since 2024", "until 2025-06").
|
|
1640
|
+
Omit "eventTime" when the fact has no explicit temporal anchor — do NOT guess or infer dates. The system resolves the expression against the conversation's own timestamp, not today's date.
|
|
1641
|
+
`;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1598
1644
|
/**
|
|
1599
1645
|
* Build extraction instructions shared between local and cloud LLM.
|
|
1600
1646
|
*/
|
|
@@ -1663,6 +1709,7 @@ ${existingEntities.join(", ")}
|
|
|
1663
1709
|
|
|
1664
1710
|
When you see something that matches a known entity, use THAT name exactly. Only create a NEW entity if nothing in this list represents it.
|
|
1665
1711
|
` : ""}
|
|
1712
|
+
${this.eventTimePromptInstruction()}
|
|
1666
1713
|
Also extract relationships between entities mentioned in the conversation.
|
|
1667
1714
|
- Format: {source: "entity-name", target: "entity-name", label: "relationship description"}
|
|
1668
1715
|
- Max 5 relationships per extraction
|