mem-os-python 1.6.27__py3-none-any.whl
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.
- mem_os_python-1.6.27.dist-info/METADATA +1032 -0
- mem_os_python-1.6.27.dist-info/RECORD +253 -0
- mem_os_python-1.6.27.dist-info/WHEEL +4 -0
- mem_os_python-1.6.27.dist-info/entry_points.txt +2 -0
- mem_os_python-1.6.27.dist-info/licenses/LICENSE +21 -0
- memos/__init__.py +16 -0
- memos/_js/adapters/anthropic.d.ts +279 -0
- memos/_js/adapters/anthropic.d.ts.map +1 -0
- memos/_js/adapters/anthropic.js +348 -0
- memos/_js/adapters/anthropic.js.map +1 -0
- memos/_js/adapters/base.d.ts +10 -0
- memos/_js/adapters/base.d.ts.map +1 -0
- memos/_js/adapters/base.js +2 -0
- memos/_js/adapters/base.js.map +1 -0
- memos/_js/adapters/openai.d.ts +264 -0
- memos/_js/adapters/openai.d.ts.map +1 -0
- memos/_js/adapters/openai.js +342 -0
- memos/_js/adapters/openai.js.map +1 -0
- memos/_js/apps/explorer.d.ts +244 -0
- memos/_js/apps/explorer.d.ts.map +1 -0
- memos/_js/apps/explorer.js +738 -0
- memos/_js/apps/explorer.js.map +1 -0
- memos/_js/citations.d.ts +65 -0
- memos/_js/citations.d.ts.map +1 -0
- memos/_js/citations.js +143 -0
- memos/_js/citations.js.map +1 -0
- memos/_js/cli-browse.d.ts +3 -0
- memos/_js/cli-browse.d.ts.map +1 -0
- memos/_js/cli-browse.js +129 -0
- memos/_js/cli-browse.js.map +1 -0
- memos/_js/cli-completion.d.ts +31 -0
- memos/_js/cli-completion.d.ts.map +1 -0
- memos/_js/cli-completion.js +340 -0
- memos/_js/cli-completion.js.map +1 -0
- memos/_js/cli-help.d.ts +18 -0
- memos/_js/cli-help.d.ts.map +1 -0
- memos/_js/cli-help.js +357 -0
- memos/_js/cli-help.js.map +1 -0
- memos/_js/cli.d.ts +28 -0
- memos/_js/cli.d.ts.map +1 -0
- memos/_js/cli.js +2880 -0
- memos/_js/cli.js.map +1 -0
- memos/_js/compression.d.ts +25 -0
- memos/_js/compression.d.ts.map +1 -0
- memos/_js/compression.js +319 -0
- memos/_js/compression.js.map +1 -0
- memos/_js/confidence-machine.d.ts +99 -0
- memos/_js/confidence-machine.d.ts.map +1 -0
- memos/_js/confidence-machine.js +222 -0
- memos/_js/confidence-machine.js.map +1 -0
- memos/_js/context-pack.d.ts +506 -0
- memos/_js/context-pack.d.ts.map +1 -0
- memos/_js/context-pack.js +1435 -0
- memos/_js/context-pack.js.map +1 -0
- memos/_js/contradictions.d.ts +160 -0
- memos/_js/contradictions.d.ts.map +1 -0
- memos/_js/contradictions.js +255 -0
- memos/_js/contradictions.js.map +1 -0
- memos/_js/dashboard.d.ts +30 -0
- memos/_js/dashboard.d.ts.map +1 -0
- memos/_js/dashboard.js +302 -0
- memos/_js/dashboard.js.map +1 -0
- memos/_js/ebbinghaus.d.ts +29 -0
- memos/_js/ebbinghaus.d.ts.map +1 -0
- memos/_js/ebbinghaus.js +32 -0
- memos/_js/ebbinghaus.js.map +1 -0
- memos/_js/embedding-queue.d.ts +190 -0
- memos/_js/embedding-queue.d.ts.map +1 -0
- memos/_js/embedding-queue.js +316 -0
- memos/_js/embedding-queue.js.map +1 -0
- memos/_js/embeddings.d.ts +187 -0
- memos/_js/embeddings.d.ts.map +1 -0
- memos/_js/embeddings.js +633 -0
- memos/_js/embeddings.js.map +1 -0
- memos/_js/entity-extraction.d.ts +54 -0
- memos/_js/entity-extraction.d.ts.map +1 -0
- memos/_js/entity-extraction.js +325 -0
- memos/_js/entity-extraction.js.map +1 -0
- memos/_js/entity-index.d.ts +93 -0
- memos/_js/entity-index.d.ts.map +1 -0
- memos/_js/entity-index.js +165 -0
- memos/_js/entity-index.js.map +1 -0
- memos/_js/event-memory.d.ts +147 -0
- memos/_js/event-memory.d.ts.map +1 -0
- memos/_js/event-memory.js +290 -0
- memos/_js/event-memory.js.map +1 -0
- memos/_js/external-import.d.ts +98 -0
- memos/_js/external-import.d.ts.map +1 -0
- memos/_js/external-import.js +669 -0
- memos/_js/external-import.js.map +1 -0
- memos/_js/fidelity.d.ts +367 -0
- memos/_js/fidelity.d.ts.map +1 -0
- memos/_js/fidelity.js +911 -0
- memos/_js/fidelity.js.map +1 -0
- memos/_js/graph-expansion.d.ts +119 -0
- memos/_js/graph-expansion.d.ts.map +1 -0
- memos/_js/graph-expansion.js +213 -0
- memos/_js/graph-expansion.js.map +1 -0
- memos/_js/graph-mermaid.d.ts +13 -0
- memos/_js/graph-mermaid.d.ts.map +1 -0
- memos/_js/graph-mermaid.js +32 -0
- memos/_js/graph-mermaid.js.map +1 -0
- memos/_js/graph.d.ts +170 -0
- memos/_js/graph.d.ts.map +1 -0
- memos/_js/graph.js +482 -0
- memos/_js/graph.js.map +1 -0
- memos/_js/harness.d.ts +63 -0
- memos/_js/harness.d.ts.map +1 -0
- memos/_js/harness.js +93 -0
- memos/_js/harness.js.map +1 -0
- memos/_js/importance.d.ts +118 -0
- memos/_js/importance.d.ts.map +1 -0
- memos/_js/importance.js +144 -0
- memos/_js/importance.js.map +1 -0
- memos/_js/index.d.ts +51 -0
- memos/_js/index.d.ts.map +1 -0
- memos/_js/index.js +53 -0
- memos/_js/index.js.map +1 -0
- memos/_js/mcp.d.ts +58 -0
- memos/_js/mcp.d.ts.map +1 -0
- memos/_js/mcp.js +1853 -0
- memos/_js/mcp.js.map +1 -0
- memos/_js/memory.d.ts +1762 -0
- memos/_js/memory.d.ts.map +1 -0
- memos/_js/memory.js +6283 -0
- memos/_js/memory.js.map +1 -0
- memos/_js/procedural.d.ts +74 -0
- memos/_js/procedural.d.ts.map +1 -0
- memos/_js/procedural.js +125 -0
- memos/_js/procedural.js.map +1 -0
- memos/_js/project-config.d.ts +68 -0
- memos/_js/project-config.d.ts.map +1 -0
- memos/_js/project-config.js +59 -0
- memos/_js/project-config.js.map +1 -0
- memos/_js/proof-of-forgetting.d.ts +57 -0
- memos/_js/proof-of-forgetting.d.ts.map +1 -0
- memos/_js/proof-of-forgetting.js +80 -0
- memos/_js/proof-of-forgetting.js.map +1 -0
- memos/_js/provenance.d.ts +122 -0
- memos/_js/provenance.d.ts.map +1 -0
- memos/_js/provenance.js +182 -0
- memos/_js/provenance.js.map +1 -0
- memos/_js/quarantine-commands.d.ts +23 -0
- memos/_js/quarantine-commands.d.ts.map +1 -0
- memos/_js/quarantine-commands.js +42 -0
- memos/_js/quarantine-commands.js.map +1 -0
- memos/_js/quarantine.d.ts +120 -0
- memos/_js/quarantine.d.ts.map +1 -0
- memos/_js/quarantine.js +873 -0
- memos/_js/quarantine.js.map +1 -0
- memos/_js/redact.d.ts +12 -0
- memos/_js/redact.d.ts.map +1 -0
- memos/_js/redact.js +26 -0
- memos/_js/redact.js.map +1 -0
- memos/_js/repl.d.ts +57 -0
- memos/_js/repl.d.ts.map +1 -0
- memos/_js/repl.js +295 -0
- memos/_js/repl.js.map +1 -0
- memos/_js/rerank-local.d.ts +61 -0
- memos/_js/rerank-local.d.ts.map +1 -0
- memos/_js/rerank-local.js +210 -0
- memos/_js/rerank-local.js.map +1 -0
- memos/_js/retain-filter.d.ts +98 -0
- memos/_js/retain-filter.d.ts.map +1 -0
- memos/_js/retain-filter.js +232 -0
- memos/_js/retain-filter.js.map +1 -0
- memos/_js/retrieval.d.ts +265 -0
- memos/_js/retrieval.d.ts.map +1 -0
- memos/_js/retrieval.js +1018 -0
- memos/_js/retrieval.js.map +1 -0
- memos/_js/revert.d.ts +77 -0
- memos/_js/revert.d.ts.map +1 -0
- memos/_js/revert.js +252 -0
- memos/_js/revert.js.map +1 -0
- memos/_js/scope.d.ts +30 -0
- memos/_js/scope.d.ts.map +1 -0
- memos/_js/scope.js +71 -0
- memos/_js/scope.js.map +1 -0
- memos/_js/semantic-screen.d.ts +152 -0
- memos/_js/semantic-screen.d.ts.map +1 -0
- memos/_js/semantic-screen.js +290 -0
- memos/_js/semantic-screen.js.map +1 -0
- memos/_js/session-hooks.d.ts +127 -0
- memos/_js/session-hooks.d.ts.map +1 -0
- memos/_js/session-hooks.js +482 -0
- memos/_js/session-hooks.js.map +1 -0
- memos/_js/storage/sqlite.d.ts +427 -0
- memos/_js/storage/sqlite.d.ts.map +1 -0
- memos/_js/storage/sqlite.js +2428 -0
- memos/_js/storage/sqlite.js.map +1 -0
- memos/_js/sync.d.ts +213 -0
- memos/_js/sync.d.ts.map +1 -0
- memos/_js/sync.js +389 -0
- memos/_js/sync.js.map +1 -0
- memos/_js/tamper-log.d.ts +98 -0
- memos/_js/tamper-log.d.ts.map +1 -0
- memos/_js/tamper-log.js +327 -0
- memos/_js/tamper-log.js.map +1 -0
- memos/_js/temporal.d.ts +92 -0
- memos/_js/temporal.d.ts.map +1 -0
- memos/_js/temporal.js +536 -0
- memos/_js/temporal.js.map +1 -0
- memos/_js/time-travel.d.ts +38 -0
- memos/_js/time-travel.d.ts.map +1 -0
- memos/_js/time-travel.js +46 -0
- memos/_js/time-travel.js.map +1 -0
- memos/_js/timestamp-format.d.ts +18 -0
- memos/_js/timestamp-format.d.ts.map +1 -0
- memos/_js/timestamp-format.js +52 -0
- memos/_js/timestamp-format.js.map +1 -0
- memos/_js/triple-extraction.d.ts +31 -0
- memos/_js/triple-extraction.d.ts.map +1 -0
- memos/_js/triple-extraction.js +116 -0
- memos/_js/triple-extraction.js.map +1 -0
- memos/_js/types.d.ts +2474 -0
- memos/_js/types.d.ts.map +1 -0
- memos/_js/types.js +20 -0
- memos/_js/types.js.map +1 -0
- memos/_js/updater.d.ts +95 -0
- memos/_js/updater.d.ts.map +1 -0
- memos/_js/updater.js +268 -0
- memos/_js/updater.js.map +1 -0
- memos/_js/version.d.ts +17 -0
- memos/_js/version.d.ts.map +1 -0
- memos/_js/version.js +34 -0
- memos/_js/version.js.map +1 -0
- memos/_js/vision/clip-query-cache.d.ts +58 -0
- memos/_js/vision/clip-query-cache.d.ts.map +1 -0
- memos/_js/vision/clip-query-cache.js +79 -0
- memos/_js/vision/clip-query-cache.js.map +1 -0
- memos/_js/vision/clip.d.ts +113 -0
- memos/_js/vision/clip.d.ts.map +1 -0
- memos/_js/vision/clip.js +224 -0
- memos/_js/vision/clip.js.map +1 -0
- memos/_js/vision/fake-clip.d.ts +55 -0
- memos/_js/vision/fake-clip.d.ts.map +1 -0
- memos/_js/vision/fake-clip.js +122 -0
- memos/_js/vision/fake-clip.js.map +1 -0
- memos/_js/vision/index.d.ts +15 -0
- memos/_js/vision/index.d.ts.map +1 -0
- memos/_js/vision/index.js +13 -0
- memos/_js/vision/index.js.map +1 -0
- memos/_js/vision/store.d.ts +137 -0
- memos/_js/vision/store.d.ts.map +1 -0
- memos/_js/vision/store.js +383 -0
- memos/_js/vision/store.js.map +1 -0
- memos/adapters/__init__.py +0 -0
- memos/adapters/crewai.py +385 -0
- memos/adapters/langchain.py +301 -0
- memos/adapters/ollama.py +396 -0
- memos/server/__init__.py +0 -0
- memos/server/main.py +547 -0
- memos/server/routes.py +360 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic temporal event memory: extraction, update/cancel
|
|
3
|
+
* resolution, and reminder listing. No LLM on any path — regex intent
|
|
4
|
+
* detection plus the deterministic parser in `./temporal.js`, mirroring
|
|
5
|
+
* the `src/revert.ts` pattern.
|
|
6
|
+
*
|
|
7
|
+
* Cross-harness continuity: every harness (any model, any process) shares
|
|
8
|
+
* the same DB file and runs the same parsing/resolution rules, so an
|
|
9
|
+
* event stored by model A is updatable by model B. The update path reads
|
|
10
|
+
* the event's CURRENT row from the store (not from conversation state),
|
|
11
|
+
* so there is no per-harness state to drift.
|
|
12
|
+
*
|
|
13
|
+
* @module @memos/event-memory
|
|
14
|
+
*/
|
|
15
|
+
import { type TemporalDuration, type TemporalGrain } from "./temporal.js";
|
|
16
|
+
import type { MemoryNode, ScoredMemory, SearchFilter } from "./types.js";
|
|
17
|
+
/** Event status lifecycle. */
|
|
18
|
+
export type EventStatus = "scheduled" | "recurring" | "cancelled";
|
|
19
|
+
/**
|
|
20
|
+
* Structured event payload stored in `metadata.event`.
|
|
21
|
+
*
|
|
22
|
+
* - `kind`: canonical event noun ("meeting", "appointment", "reminder").
|
|
23
|
+
* - `label`: human noun phrase ("meeting", "dentist appointment").
|
|
24
|
+
* - `at`: ISO-8601 datetime of the event.
|
|
25
|
+
* - `grain`: temporal resolution of the parse.
|
|
26
|
+
* - `status`: "scheduled" events feed reminders; "recurring" (year-less
|
|
27
|
+
* or every-X references) and "cancelled" never do.
|
|
28
|
+
* - `reminder_at`: ISO-8601; when the reminder fires (defaults to `at`).
|
|
29
|
+
*/
|
|
30
|
+
export interface EventMetadata {
|
|
31
|
+
kind: string;
|
|
32
|
+
label: string;
|
|
33
|
+
at: string;
|
|
34
|
+
grain: TemporalGrain;
|
|
35
|
+
status: EventStatus;
|
|
36
|
+
reminder_at: string;
|
|
37
|
+
}
|
|
38
|
+
/** Result of `detectEvent`. */
|
|
39
|
+
export interface DetectedEvent extends EventMetadata {
|
|
40
|
+
}
|
|
41
|
+
/** A natural-language event update or cancellation. */
|
|
42
|
+
export interface EventUpdate {
|
|
43
|
+
intent: "update" | "cancel";
|
|
44
|
+
/** Named event kind ("meeting"), absent for bare "it". */
|
|
45
|
+
kind?: string;
|
|
46
|
+
/** New absolute-ish time (parsed against `now`), for updates. */
|
|
47
|
+
newTime?: {
|
|
48
|
+
at: string;
|
|
49
|
+
grain: TemporalGrain;
|
|
50
|
+
};
|
|
51
|
+
/** Bare relative offset ("3 days later") — anchored to the EVENT's
|
|
52
|
+
* current datetime, not to now. */
|
|
53
|
+
duration?: TemporalDuration;
|
|
54
|
+
/** Name of the pattern that fired (debugging / docs). */
|
|
55
|
+
pattern: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Detect a schedulable event in free text: an event noun co-occurring
|
|
59
|
+
* with a temporal expression.
|
|
60
|
+
*
|
|
61
|
+
* Guard (deterministic): dates without a year ("my birthday is June 1")
|
|
62
|
+
* or recurring references ("every Monday") yield `status: "recurring"` —
|
|
63
|
+
* they are stored as structured events but NEVER produce reminders.
|
|
64
|
+
*
|
|
65
|
+
* @param content — The memory text.
|
|
66
|
+
* @param now — Reference time for temporal parsing.
|
|
67
|
+
* @returns The detected event, or null when no event noun + temporal
|
|
68
|
+
* expression co-occur.
|
|
69
|
+
*/
|
|
70
|
+
export declare function detectEvent(content: string, now: Date): DetectedEvent | null;
|
|
71
|
+
/**
|
|
72
|
+
* Detect an event update/cancellation command in free text.
|
|
73
|
+
*
|
|
74
|
+
* Returns null when: no update/cancel intent; intent present but no
|
|
75
|
+
* resolvable new time (fail safe — the write proceeds as a normal
|
|
76
|
+
* memory); or the text names no actionable target. An update intent
|
|
77
|
+
* WITHOUT a new time or duration is not an update — e.g. "we moved the
|
|
78
|
+
* meeting" (no when) must not touch the stored event.
|
|
79
|
+
*
|
|
80
|
+
* @param content — The memory text.
|
|
81
|
+
* @param now — Reference time for absolute-ish new times.
|
|
82
|
+
*/
|
|
83
|
+
export declare function detectEventUpdate(content: string, now: Date): EventUpdate | null;
|
|
84
|
+
/**
|
|
85
|
+
* Extract the named event kind from an update/cancel utterance.
|
|
86
|
+
* "that meeting" → "meeting"; "the dentist appointment" → "appointment";
|
|
87
|
+
* bare "it" → undefined.
|
|
88
|
+
*/
|
|
89
|
+
export declare function extractEventKind(content: string): string | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* Split a `memos remind "<text>" at <temporal-expression>` command.
|
|
92
|
+
* The temporal expression is the text after the LAST " at " whose suffix
|
|
93
|
+
* parses as a temporal expression (deterministic).
|
|
94
|
+
*
|
|
95
|
+
* @returns `{ text, temporal }`, or null when no trailing temporal
|
|
96
|
+
* expression is found.
|
|
97
|
+
*/
|
|
98
|
+
export declare function splitRemindText(input: string): {
|
|
99
|
+
text: string;
|
|
100
|
+
temporal: string;
|
|
101
|
+
} | null;
|
|
102
|
+
/** True when the node is a currently-open scheduled event. */
|
|
103
|
+
export declare function isScheduledEventNode(node: MemoryNode): boolean;
|
|
104
|
+
/** Minimal read surface `listReminders` needs (MemOS satisfies it). */
|
|
105
|
+
export interface ReminderSource {
|
|
106
|
+
search(filter: SearchFilter): Promise<ScoredMemory[]>;
|
|
107
|
+
}
|
|
108
|
+
export interface ListRemindersOptions {
|
|
109
|
+
/** Reference time ("now"); Date or Unix ms. */
|
|
110
|
+
now: Date | number;
|
|
111
|
+
/** When true, only reminders with reminder_at <= now. */
|
|
112
|
+
dueOnly?: boolean;
|
|
113
|
+
/** Namespace to scan (default: all namespaces). */
|
|
114
|
+
namespace?: string;
|
|
115
|
+
/** Scan cap (default 10_000 — same local-scan approach as other
|
|
116
|
+
* maintenance passes in the codebase; v1 simplicity over an index). */
|
|
117
|
+
limit?: number;
|
|
118
|
+
}
|
|
119
|
+
export interface ReminderEntry {
|
|
120
|
+
id: string;
|
|
121
|
+
kind: string;
|
|
122
|
+
label: string;
|
|
123
|
+
at: string;
|
|
124
|
+
grain: TemporalGrain;
|
|
125
|
+
reminderAt: string;
|
|
126
|
+
content: string;
|
|
127
|
+
createdAt: number;
|
|
128
|
+
/** True when reminderAt <= now at listing time. */
|
|
129
|
+
due: boolean;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* List scheduled event reminders.
|
|
133
|
+
*
|
|
134
|
+
* Scans currently-valid (valid_to null), non-quarantined nodes carrying
|
|
135
|
+
* `metadata.event.status === "scheduled"`. Deterministic ordering:
|
|
136
|
+
* reminder_at ascending, then createdAt ascending, then id ascending.
|
|
137
|
+
*
|
|
138
|
+
* v1 note: this is a full local scan (like the decay/consolidation
|
|
139
|
+
* passes), not an index lookup — fine for a local-first store, revisit
|
|
140
|
+
* with a metadata index if reminder volume grows.
|
|
141
|
+
*
|
|
142
|
+
* Honest scope: MemOS SURFACES due reminders; it does not push-notify.
|
|
143
|
+
* Delivery/notification is the harness's job — poll `memos_reminders`
|
|
144
|
+
* (or `memos reminders --due`) on the harness's own schedule.
|
|
145
|
+
*/
|
|
146
|
+
export declare function listReminders(source: ReminderSource, opts: ListRemindersOptions): Promise<ReminderEntry[]>;
|
|
147
|
+
//# sourceMappingURL=event-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-memory.d.ts","sourceRoot":"","sources":["../src/event-memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzE,8BAA8B;AAC9B,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAElE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,+BAA+B;AAC/B,MAAM,WAAW,aAAc,SAAQ,aAAa;CAAG;AAEvD,uDAAuD;AACvD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAE,CAAC;IAC/C;wCACoC;IACpC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;CACjB;AA0DD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,aAAa,GAAG,IAAI,CA4B5E;AA6BD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,IAAI,GACR,WAAW,GAAG,IAAI,CAuCpB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWpE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CAmBP;AAED,8DAA8D;AAC9D,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAW9D;AAED,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,GAAG,EAAE,IAAI,GAAG,MAAM,CAAC;IACnB,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;4EACwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,GAAG,EAAE,OAAO,CAAC;CACd;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,aAAa,EAAE,CAAC,CAiC1B"}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic temporal event memory: extraction, update/cancel
|
|
3
|
+
* resolution, and reminder listing. No LLM on any path — regex intent
|
|
4
|
+
* detection plus the deterministic parser in `./temporal.js`, mirroring
|
|
5
|
+
* the `src/revert.ts` pattern.
|
|
6
|
+
*
|
|
7
|
+
* Cross-harness continuity: every harness (any model, any process) shares
|
|
8
|
+
* the same DB file and runs the same parsing/resolution rules, so an
|
|
9
|
+
* event stored by model A is updatable by model B. The update path reads
|
|
10
|
+
* the event's CURRENT row from the store (not from conversation state),
|
|
11
|
+
* so there is no per-harness state to drift.
|
|
12
|
+
*
|
|
13
|
+
* @module @memos/event-memory
|
|
14
|
+
*/
|
|
15
|
+
import { parseTemporal, parseDuration, } from "./temporal.js";
|
|
16
|
+
// Event nouns that make a memory an event when co-occurring with a
|
|
17
|
+
// temporal expression. Kept to concrete, schedulable nouns — notably NOT
|
|
18
|
+
// "birthday" (year-less by nature; see the recurring rule below).
|
|
19
|
+
const EVENT_NOUNS = [
|
|
20
|
+
"meeting",
|
|
21
|
+
"call",
|
|
22
|
+
"appointment",
|
|
23
|
+
"deadline",
|
|
24
|
+
"flight",
|
|
25
|
+
"interview",
|
|
26
|
+
"dinner",
|
|
27
|
+
"lunch",
|
|
28
|
+
"breakfast",
|
|
29
|
+
"brunch",
|
|
30
|
+
"coffee",
|
|
31
|
+
"standup",
|
|
32
|
+
"review",
|
|
33
|
+
"doctor",
|
|
34
|
+
"dentist",
|
|
35
|
+
"party",
|
|
36
|
+
"class",
|
|
37
|
+
"lesson",
|
|
38
|
+
"exam",
|
|
39
|
+
"presentation",
|
|
40
|
+
"demo",
|
|
41
|
+
"sync",
|
|
42
|
+
"workshop",
|
|
43
|
+
"conference",
|
|
44
|
+
"webinar",
|
|
45
|
+
"session",
|
|
46
|
+
"trip",
|
|
47
|
+
"wedding",
|
|
48
|
+
"checkup",
|
|
49
|
+
"reminder",
|
|
50
|
+
"1:1",
|
|
51
|
+
];
|
|
52
|
+
const EVENT_NOUN_SET = new Set(EVENT_NOUNS);
|
|
53
|
+
// "dentist appointment" / "team meeting" style compounds: the modifier is
|
|
54
|
+
// kept in the label, the head noun is the kind.
|
|
55
|
+
const COMPOUND_RE = new RegExp(String.raw `\b(dentist|doctor|team|standup|project|client)\s+(appointment|meeting|call|review|sync|session)\b`, "i");
|
|
56
|
+
const NOUN_RE = new RegExp(String.raw `\b(${EVENT_NOUNS.map((n) => n.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\b`, "i");
|
|
57
|
+
// Year-less / repeating references never become scheduled reminders.
|
|
58
|
+
const RECURRING_RE = /\b(every|each)\b|\b(daily|weekly|monthly|yearly|annually)\b/i;
|
|
59
|
+
/**
|
|
60
|
+
* Detect a schedulable event in free text: an event noun co-occurring
|
|
61
|
+
* with a temporal expression.
|
|
62
|
+
*
|
|
63
|
+
* Guard (deterministic): dates without a year ("my birthday is June 1")
|
|
64
|
+
* or recurring references ("every Monday") yield `status: "recurring"` —
|
|
65
|
+
* they are stored as structured events but NEVER produce reminders.
|
|
66
|
+
*
|
|
67
|
+
* @param content — The memory text.
|
|
68
|
+
* @param now — Reference time for temporal parsing.
|
|
69
|
+
* @returns The detected event, or null when no event noun + temporal
|
|
70
|
+
* expression co-occur.
|
|
71
|
+
*/
|
|
72
|
+
export function detectEvent(content, now) {
|
|
73
|
+
if (!content || typeof content !== "string")
|
|
74
|
+
return null;
|
|
75
|
+
const compound = COMPOUND_RE.exec(content);
|
|
76
|
+
const nounMatch = compound ?? NOUN_RE.exec(content);
|
|
77
|
+
if (!nounMatch)
|
|
78
|
+
return null;
|
|
79
|
+
const parsed = parseTemporal(content, now);
|
|
80
|
+
if (!parsed)
|
|
81
|
+
return null;
|
|
82
|
+
let kind;
|
|
83
|
+
let label;
|
|
84
|
+
if (compound) {
|
|
85
|
+
kind = compound[2].toLowerCase();
|
|
86
|
+
label = `${compound[1].toLowerCase()} ${kind}`;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
kind = nounMatch[1].toLowerCase();
|
|
90
|
+
label = kind;
|
|
91
|
+
}
|
|
92
|
+
const recurring = RECURRING_RE.test(content) || !parsed.yearCertain;
|
|
93
|
+
const at = parsed.at.toISOString();
|
|
94
|
+
return {
|
|
95
|
+
kind,
|
|
96
|
+
label,
|
|
97
|
+
at,
|
|
98
|
+
grain: parsed.grain,
|
|
99
|
+
status: recurring ? "recurring" : "scheduled",
|
|
100
|
+
reminder_at: at,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// Update-intent verbs. Evaluation order: cancel patterns run BEFORE
|
|
104
|
+
// update patterns (a cancellation is terminal — "moved then cancelled"
|
|
105
|
+
// must cancel, never reschedule).
|
|
106
|
+
const CANCEL_PATTERNS = [
|
|
107
|
+
{ name: "cancelled", regex: /\b(cancelled|canceled|cancel)\b/i },
|
|
108
|
+
{ name: "called-off", regex: /\bcalled\s+off\b/i },
|
|
109
|
+
// "never mind, forget about that meeting" — cancel-scoped "never mind".
|
|
110
|
+
// (Bare "never mind that" without a cancel verb is NOT a cancel; the
|
|
111
|
+
// revert module owns that phrasing.)
|
|
112
|
+
{ name: "never-mind-cancel", regex: /\bnever\s+mind\b.{0,40}\bcancel\b/i },
|
|
113
|
+
];
|
|
114
|
+
const UPDATE_PATTERNS = [
|
|
115
|
+
{ name: "rescheduled", regex: /\breschedul(?:ed|e|ing)\b/i },
|
|
116
|
+
{ name: "postponed", regex: /\bpostponed?\b/i },
|
|
117
|
+
{ name: "moved", regex: /\bmoved?\b/i },
|
|
118
|
+
{ name: "pushed", regex: /\bpushed?\s+(?:back|forward|up|to)?\b/i },
|
|
119
|
+
{ name: "changed-to", regex: /\bchanged?\s+to\b/i },
|
|
120
|
+
// "actually the meeting is at 3pm now" — explicit new time.
|
|
121
|
+
{ name: "actually-at", regex: /\bactually\b.{0,60}\bat\s+\d/i },
|
|
122
|
+
];
|
|
123
|
+
// Target extraction: "that meeting", "the dentist appointment", "my call".
|
|
124
|
+
// "it" alone carries no kind (falls back to the single-open-event rule).
|
|
125
|
+
const KIND_TARGET_RE = /\b(?:that|the|this|my|our|your)\s+([a-z][a-z0-9]*(?:\s+[a-z][a-z0-9]*)?)\b/i;
|
|
126
|
+
/**
|
|
127
|
+
* Detect an event update/cancellation command in free text.
|
|
128
|
+
*
|
|
129
|
+
* Returns null when: no update/cancel intent; intent present but no
|
|
130
|
+
* resolvable new time (fail safe — the write proceeds as a normal
|
|
131
|
+
* memory); or the text names no actionable target. An update intent
|
|
132
|
+
* WITHOUT a new time or duration is not an update — e.g. "we moved the
|
|
133
|
+
* meeting" (no when) must not touch the stored event.
|
|
134
|
+
*
|
|
135
|
+
* @param content — The memory text.
|
|
136
|
+
* @param now — Reference time for absolute-ish new times.
|
|
137
|
+
*/
|
|
138
|
+
export function detectEventUpdate(content, now) {
|
|
139
|
+
if (!content || typeof content !== "string")
|
|
140
|
+
return null;
|
|
141
|
+
const kind = extractEventKind(content);
|
|
142
|
+
for (const pattern of CANCEL_PATTERNS) {
|
|
143
|
+
if (pattern.regex.test(content)) {
|
|
144
|
+
const update = { intent: "cancel", pattern: pattern.name };
|
|
145
|
+
if (kind)
|
|
146
|
+
update.kind = kind;
|
|
147
|
+
return update;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const pattern of UPDATE_PATTERNS) {
|
|
151
|
+
if (pattern.regex.test(content)) {
|
|
152
|
+
// Bare relative offset anchors to the EVENT's datetime, not now.
|
|
153
|
+
const duration = parseDuration(content);
|
|
154
|
+
if (duration) {
|
|
155
|
+
const update = {
|
|
156
|
+
intent: "update",
|
|
157
|
+
duration,
|
|
158
|
+
pattern: `${pattern.name}+duration`,
|
|
159
|
+
};
|
|
160
|
+
if (kind)
|
|
161
|
+
update.kind = kind;
|
|
162
|
+
return update;
|
|
163
|
+
}
|
|
164
|
+
// Otherwise parse absolute-ish against now ("moved to Friday").
|
|
165
|
+
const parsed = parseTemporal(content, now);
|
|
166
|
+
if (!parsed)
|
|
167
|
+
return null; // intent but no time → fail safe
|
|
168
|
+
const update = {
|
|
169
|
+
intent: "update",
|
|
170
|
+
newTime: { at: parsed.at.toISOString(), grain: parsed.grain },
|
|
171
|
+
pattern: pattern.name,
|
|
172
|
+
};
|
|
173
|
+
if (kind)
|
|
174
|
+
update.kind = kind;
|
|
175
|
+
return update;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Extract the named event kind from an update/cancel utterance.
|
|
182
|
+
* "that meeting" → "meeting"; "the dentist appointment" → "appointment";
|
|
183
|
+
* bare "it" → undefined.
|
|
184
|
+
*/
|
|
185
|
+
export function extractEventKind(content) {
|
|
186
|
+
const m = KIND_TARGET_RE.exec(content);
|
|
187
|
+
if (!m?.[1])
|
|
188
|
+
return undefined;
|
|
189
|
+
const phrase = m[1].toLowerCase().trim();
|
|
190
|
+
const words = phrase.split(/\s+/);
|
|
191
|
+
const head = words[words.length - 1];
|
|
192
|
+
if (EVENT_NOUN_SET.has(head))
|
|
193
|
+
return head;
|
|
194
|
+
// Modifier-first phrasing ("that dentist") — accept the modifier when
|
|
195
|
+
// it is itself an event noun.
|
|
196
|
+
if (words.length > 1 && EVENT_NOUN_SET.has(words[0]))
|
|
197
|
+
return words[0];
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Split a `memos remind "<text>" at <temporal-expression>` command.
|
|
202
|
+
* The temporal expression is the text after the LAST " at " whose suffix
|
|
203
|
+
* parses as a temporal expression (deterministic).
|
|
204
|
+
*
|
|
205
|
+
* @returns `{ text, temporal }`, or null when no trailing temporal
|
|
206
|
+
* expression is found.
|
|
207
|
+
*/
|
|
208
|
+
export function splitRemindText(input) {
|
|
209
|
+
if (!input || typeof input !== "string")
|
|
210
|
+
return null;
|
|
211
|
+
// Walk " at " occurrences right-to-left; the first (rightmost) suffix
|
|
212
|
+
// that parses wins.
|
|
213
|
+
const lower = input.toLowerCase();
|
|
214
|
+
let idx = lower.lastIndexOf(" at ");
|
|
215
|
+
while (idx !== -1) {
|
|
216
|
+
const text = input.slice(0, idx).trim();
|
|
217
|
+
const temporal = input.slice(idx + 4).trim();
|
|
218
|
+
if (text.length > 0 && temporal.length > 0) {
|
|
219
|
+
// Suffix must parse against an arbitrary fixed reference — the
|
|
220
|
+
// parse here only validates shape, not the resolved datetime.
|
|
221
|
+
if (parseTemporal(temporal, new Date(2026, 0, 1, 12, 0, 0))) {
|
|
222
|
+
return { text, temporal };
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
idx = lower.lastIndexOf(" at ", idx - 1);
|
|
226
|
+
}
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
/** True when the node is a currently-open scheduled event. */
|
|
230
|
+
export function isScheduledEventNode(node) {
|
|
231
|
+
const event = node.metadata
|
|
232
|
+
?.event;
|
|
233
|
+
return (node.validTo === null &&
|
|
234
|
+
node.quarantined === false &&
|
|
235
|
+
typeof event === "object" &&
|
|
236
|
+
event !== null &&
|
|
237
|
+
event.status === "scheduled" &&
|
|
238
|
+
typeof event.reminder_at === "string");
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* List scheduled event reminders.
|
|
242
|
+
*
|
|
243
|
+
* Scans currently-valid (valid_to null), non-quarantined nodes carrying
|
|
244
|
+
* `metadata.event.status === "scheduled"`. Deterministic ordering:
|
|
245
|
+
* reminder_at ascending, then createdAt ascending, then id ascending.
|
|
246
|
+
*
|
|
247
|
+
* v1 note: this is a full local scan (like the decay/consolidation
|
|
248
|
+
* passes), not an index lookup — fine for a local-first store, revisit
|
|
249
|
+
* with a metadata index if reminder volume grows.
|
|
250
|
+
*
|
|
251
|
+
* Honest scope: MemOS SURFACES due reminders; it does not push-notify.
|
|
252
|
+
* Delivery/notification is the harness's job — poll `memos_reminders`
|
|
253
|
+
* (or `memos reminders --due`) on the harness's own schedule.
|
|
254
|
+
*/
|
|
255
|
+
export async function listReminders(source, opts) {
|
|
256
|
+
const nowMs = opts.now instanceof Date ? opts.now.getTime() : opts.now;
|
|
257
|
+
const filter = { limit: opts.limit ?? 10_000 };
|
|
258
|
+
if (opts.namespace !== undefined)
|
|
259
|
+
filter.namespace = opts.namespace;
|
|
260
|
+
const rows = await source.search(filter);
|
|
261
|
+
const entries = [];
|
|
262
|
+
for (const { node } of rows) {
|
|
263
|
+
if (!isScheduledEventNode(node))
|
|
264
|
+
continue;
|
|
265
|
+
const event = node.metadata.event;
|
|
266
|
+
const reminderMs = new Date(event.reminder_at).getTime();
|
|
267
|
+
if (Number.isNaN(reminderMs))
|
|
268
|
+
continue;
|
|
269
|
+
const due = reminderMs <= nowMs;
|
|
270
|
+
if (opts.dueOnly && !due)
|
|
271
|
+
continue;
|
|
272
|
+
entries.push({
|
|
273
|
+
id: node.id,
|
|
274
|
+
kind: event.kind,
|
|
275
|
+
label: event.label,
|
|
276
|
+
at: event.at,
|
|
277
|
+
grain: event.grain,
|
|
278
|
+
reminderAt: event.reminder_at,
|
|
279
|
+
content: node.content,
|
|
280
|
+
createdAt: node.createdAt,
|
|
281
|
+
due,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
// Deterministic order: reminder time, then creation time, then id.
|
|
285
|
+
entries.sort((a, b) => new Date(a.reminderAt).getTime() - new Date(b.reminderAt).getTime() ||
|
|
286
|
+
a.createdAt - b.createdAt ||
|
|
287
|
+
(a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
288
|
+
return entries;
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=event-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-memory.js","sourceRoot":"","sources":["../src/event-memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser for third-party AI memory exports — ChatGPT data exports and
|
|
3
|
+
* Claude data exports — feeding `MemOS.importExternal`.
|
|
4
|
+
*
|
|
5
|
+
* The design goal is tolerance: vendor export shapes change without
|
|
6
|
+
* notice, so the parser sniffs each item rather than trusting a fixed
|
|
7
|
+
* schema, extracts whatever text fields exist, and reports what it
|
|
8
|
+
* skipped. Recognized shapes:
|
|
9
|
+
*
|
|
10
|
+
* - ChatGPT data export (`conversations.json`): an array of
|
|
11
|
+
* `{ title, mapping: { <id>: { message: { author: { role }, content:
|
|
12
|
+
* { parts: string[] } } } } }` trees — user turns are extracted.
|
|
13
|
+
* - Claude data export (`conversations.json`): an array of
|
|
14
|
+
* `{ name, chat_messages: [{ sender: "human", text, created_at }] }` —
|
|
15
|
+
* human turns are extracted. A directory export is scanned for every
|
|
16
|
+
* `*.json` / `*.jsonl` file and each candidate is sniffed.
|
|
17
|
+
* - Slack export (directory): `channels.json` + `users.json` plus one
|
|
18
|
+
* folder per channel with per-day message files
|
|
19
|
+
* (`{ user, text, ts }`) — all messages are extracted with author and
|
|
20
|
+
* channel attribution.
|
|
21
|
+
* - Flat memory lists: an array of strings or of objects with
|
|
22
|
+
* `content` / `text` / `title` / `memory` string fields (covers
|
|
23
|
+
* `memories.json`-style exports from both vendors).
|
|
24
|
+
* - Wrapper objects: `{ conversations: [...] }` or `{ memories: [...] }`.
|
|
25
|
+
*
|
|
26
|
+
* Dedupe is by SHA-256 of the normalized content (whitespace-collapsed,
|
|
27
|
+
* lowercased), so the same message appearing in several files — or twice
|
|
28
|
+
* in one export — is imported once.
|
|
29
|
+
*
|
|
30
|
+
* @module @mem-os/external-import
|
|
31
|
+
*/
|
|
32
|
+
export type ExternalImportSource = "auto" | "chatgpt" | "claude" | "slack" | "generic";
|
|
33
|
+
export type DetectedExportSource = "chatgpt" | "claude" | "slack" | "generic";
|
|
34
|
+
export interface ExternalMemoryItem {
|
|
35
|
+
content: string;
|
|
36
|
+
/** Creation timestamp in Unix ms, when the export carried one. */
|
|
37
|
+
createdAt?: number;
|
|
38
|
+
/** Human-readable author name, when the export carried one. */
|
|
39
|
+
author?: string;
|
|
40
|
+
/** Channel / conversation label, when the export carried one. */
|
|
41
|
+
channel?: string;
|
|
42
|
+
/** Conversation title, when the export carried one. */
|
|
43
|
+
conversation?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface ParsedExternalExport {
|
|
46
|
+
items: ExternalMemoryItem[];
|
|
47
|
+
detected: DetectedExportSource;
|
|
48
|
+
/** Items recognized structurally but yielding no usable text. */
|
|
49
|
+
skipped: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Parse a parsed-JSON export payload into memory items.
|
|
53
|
+
*
|
|
54
|
+
* @param raw — The decoded JSON value (or a JSON string).
|
|
55
|
+
* @param source — `"auto"` sniffs the shape; explicit values force a
|
|
56
|
+
* parser (useful when auto-detection misreads a custom format).
|
|
57
|
+
*/
|
|
58
|
+
export declare function parseExternalMemoryExport(raw: unknown, source?: ExternalImportSource, maxItems?: number): ParsedExternalExport;
|
|
59
|
+
/**
|
|
60
|
+
* SHA-256 of the normalized content (whitespace-collapsed, lowercased).
|
|
61
|
+
* The dedupe key for imports.
|
|
62
|
+
*/
|
|
63
|
+
export declare function contentHash(content: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* Scan an export directory for a vendor source and parse everything
|
|
66
|
+
* found, with content-hash dedupe across files.
|
|
67
|
+
*
|
|
68
|
+
* - `slack`: reads the official Slack export layout (`channels.json`,
|
|
69
|
+
* `users.json`, per-channel per-day message files).
|
|
70
|
+
* - `chatgpt` / `claude`: walks the directory for `*.json` files
|
|
71
|
+
* (each sniffed as a conversation export) and `*.jsonl` files
|
|
72
|
+
* (each line sniffed as a message).
|
|
73
|
+
*/
|
|
74
|
+
export declare function parseExportDirectory(dir: string, source: "chatgpt" | "claude" | "slack", maxItems?: number): Promise<ParsedExternalExport>;
|
|
75
|
+
/**
|
|
76
|
+
* Parse an official Slack export directory:
|
|
77
|
+
* `channels.json` + `users.json` at the root, one folder per channel
|
|
78
|
+
* with per-day message files (`[{ user, text, ts }]`).
|
|
79
|
+
*/
|
|
80
|
+
export declare function parseSlackExportDirectory(dir: string, maxItems?: number): Promise<ParsedExternalExport>;
|
|
81
|
+
/** Structured insight extracted from imported text. */
|
|
82
|
+
export type SynthesizedKind = "decision" | "preference" | "milestone";
|
|
83
|
+
export interface SynthesizedInsight {
|
|
84
|
+
kind: SynthesizedKind;
|
|
85
|
+
/** The source sentence, trimmed (max 400 chars). */
|
|
86
|
+
text: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Rule-based post-import pass: pull structured decisions, preferences,
|
|
90
|
+
* and milestones out of imported messages. Each match is the source
|
|
91
|
+
* *sentence* (not the whole message), classified by the first matching
|
|
92
|
+
* rule (decision > preference > milestone). No LLM — pure regex over
|
|
93
|
+
* sentence-split text.
|
|
94
|
+
*/
|
|
95
|
+
export declare function synthesizeImportInsights(items: ReadonlyArray<{
|
|
96
|
+
content: string;
|
|
97
|
+
}>): SynthesizedInsight[];
|
|
98
|
+
//# sourceMappingURL=external-import.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-import.d.ts","sourceRoot":"","sources":["../src/external-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,MAAM,MAAM,oBAAoB,GAC9B,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AACtD,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAE9E,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB;AAgID;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,EACZ,MAAM,GAAE,oBAA6B,EACrC,QAAQ,SAAoB,GAC3B,oBAAoB,CAwFtB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGnD;AAQD;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,OAAO,EACtC,QAAQ,SAAoB,GAC3B,OAAO,CAAC,oBAAoB,CAAC,CA4F/B;AAkED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,MAAM,EACX,QAAQ,SAAoB,GAC3B,OAAO,CAAC,oBAAoB,CAAC,CAmI/B;AA6BD,uDAAuD;AACvD,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,CAAC;AAEtE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,eAAe,CAAC;IACtB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;CACd;AAwDD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,aAAa,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GACxC,kBAAkB,EAAE,CAgBtB"}
|