memorio 4.9.10 → 4.9.31
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/AGENTS.md +126 -126
- package/README.md +241 -100
- package/examples/basic.ts +1 -1
- package/examples/cross-platform-guards.ts +57 -57
- package/examples/multi-tenant-context.ts +44 -44
- package/examples/react-observer.tsx +63 -63
- package/examples/semantic-memory.ts +60 -60
- package/examples/session-advanced.ts +1 -1
- package/examples/sqlite-batched-writes.ts +57 -57
- package/examples/store-advanced.ts +1 -1
- package/index.cjs +74 -44
- package/index.js +74 -44
- package/llms.txt +13 -5
- package/modules/redux.cjs +2677 -0
- package/modules/redux.cjs.map +1 -0
- package/modules/redux.d.ts +119 -0
- package/modules/redux.js +2669 -0
- package/modules/redux.js.map +1 -0
- package/package.json +9 -3
- package/types/memorio.d.ts +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
# AGENTS.md
|
|
2
|
-
|
|
3
|
-
Operational conventions for AI coding agents working in a repository that depends on `memorio`.
|
|
4
|
-
See `README.md` and `llms.txt` for the full API. This file is decision rules: what to reach for,
|
|
5
|
-
when, and the specific footguns this library's own docs flag.
|
|
6
|
-
|
|
7
|
-
## Read this before generating any `memorio` code
|
|
8
|
-
|
|
9
|
-
`memorio`'s own `llms.txt` contains an explicit unresolved discrepancy:
|
|
10
|
-
|
|
11
|
-
> **Locking
|
|
12
|
-
> (`state.config.lock()` freezes only `config`); another describes global locking
|
|
13
|
-
> (`state.lock()` / `state.unlock()` freezing everything). Do not generate code against this
|
|
14
|
-
> section until it's resolved against the real source.
|
|
15
|
-
|
|
16
|
-
**Do not write or suggest `.lock()` / `.unlock()` calls with a confident claim about scope**
|
|
17
|
-
(per-key vs. global) until you've confirmed the actual signature against the installed
|
|
18
|
-
package's type definitions or source
|
|
19
|
-
If you can't confirm it, say so explicitly rather than picking one behavior and presenting it
|
|
20
|
-
as fact.
|
|
21
|
-
|
|
22
|
-
## Choosing a layer
|
|
23
|
-
|
|
24
|
-
Don't default to `state` for everything just because it's the one-liner in the README. Walk the
|
|
25
|
-
decision tree from the README's ["Which layer should I use"](./README.md#which-layer-should-i-use)
|
|
26
|
-
section, and in particular:
|
|
27
|
-
|
|
28
|
-
| If the data is... | Use | Not |
|
|
29
|
-
| --- | --- | --- |
|
|
30
|
-
| UI-reactive, doesn't need to survive reload | `state` | `store` (unnecessary persistence) |
|
|
31
|
-
| Small, must survive reload, any tab | `store` | `idb` (overkill for simple k/v) |
|
|
32
|
-
| Must survive reload, this tab only | `session` | `store` (wrong scope) |
|
|
33
|
-
| Relational, needs joins/SQL | `sqlite` | `idb` (no query language) |
|
|
34
|
-
| Structured, needs confidence/TTL/source/history | `memory` | `state`/`store` (no lifecycle semantics) |
|
|
35
|
-
| Large or structured, browser-only | `idb` | `store` (size/shape limits) |
|
|
36
|
-
|
|
37
|
-
`sqlite` and `memory` answer different questions
|
|
38
|
-
believe, and how sure is it." Don't reach for `memory` just because a value happens to come from
|
|
39
|
-
an LLM; if it doesn't need confidence scoring, TTL, or supersession history, plain `state`/`store`
|
|
40
|
-
is simpler and correct.
|
|
41
|
-
|
|
42
|
-
## Server-side and multi-request code
|
|
43
|
-
|
|
44
|
-
**`state` is a shared global namespace by default.** A value set in one request handler is
|
|
45
|
-
visible to every other read of `state` in the same process. There is no automatic per-request
|
|
46
|
-
or per-tab isolation.
|
|
47
|
-
|
|
48
|
-
Before generating any server-side code (API route, edge function, worker) that could handle more
|
|
49
|
-
than one user or request in the same process:
|
|
50
|
-
|
|
51
|
-
1. Create an explicit context per request/tenant: `const ctx = memorio.createContext(id)`, then
|
|
52
|
-
read/write via `ctx.state`, never the bare global `state`.
|
|
53
|
-
2. **Generate the context ID from trusted server-side data** (authenticated user id, request-scoped
|
|
54
|
-
token)
|
|
55
|
-
a hard boundary, so a spoofable ID is a real collision risk, not just a naming concern.
|
|
56
|
-
3. Treat context isolation as *organizational*, not a security boundary. It does not replace
|
|
57
|
-
authorization checks at the backend layer
|
|
58
|
-
one tenant's data and another's.
|
|
59
|
-
|
|
60
|
-
If the code you're generating is client-side (a single browser tab, one user), bare `state` is
|
|
61
|
-
fine
|
|
62
|
-
|
|
63
|
-
## Known rough edges
|
|
64
|
-
|
|
65
|
-
- **`store.quota()` returns `[0, 0]` for the `localStorage` backend**
|
|
66
|
-
real reading. Don't generate capacity-check logic that branches on its result for `store`.
|
|
67
|
-
It may be meaningful for `idb`, but confirm before relying on it there too.
|
|
68
|
-
- **`idb` is disabled outright in Node.js/Deno** (calls warn and no-op). Any code that might run
|
|
69
|
-
outside a guaranteed browser context must guard: `if (idb.db.support())` or check
|
|
70
|
-
`memorio.getCapabilities().hasIndexedDB`
|
|
71
|
-
anyone will see.
|
|
72
|
-
- **`sqlite` persistence serializes the entire database on every flush**
|
|
73
|
-
generate code that calls a persisting write inside a loop; batch writes in one transaction/run
|
|
74
|
-
and persist once after the batch, per the README's guidance.
|
|
75
|
-
- **`observer('state.some.path', cb)` paths are plain strings, unchecked against `state`'s actual
|
|
76
|
-
shape.** A typo or a later rename fails *silently*
|
|
77
|
-
`memorio.typed<T>()` + `registerSchema()` for anything you'd hate to have silently stop working,
|
|
78
|
-
and consider `memorio.pathExists('state.some.path')` as a startup sanity check for
|
|
79
|
-
observer-heavy code.
|
|
80
|
-
- **`memory.context()` is rule-based (tags/type/confidence/recency), not embedding-based.** Don't
|
|
81
|
-
imply semantic/meaning-based retrieval in comments or docs you generate
|
|
82
|
-
needs free-text similarity search, pair `memorio.memory` (for lifecycle: confidence, TTL,
|
|
83
|
-
supersession) with a separate embedding store, don't fake it with `context()` alone.
|
|
84
|
-
- **`memorio.logger` records the literal value written**, including tokens or PII, in
|
|
85
|
-
`getHistory()` / `exportLogs()`. Never enable it unconditionally on a production path that
|
|
86
|
-
touches sensitive data, and never wire `exportLogs()` output to analytics or error reporters
|
|
87
|
-
without redaction first.
|
|
88
|
-
- **Nothing in `store`, `session`, `idb`, or `memory` is encrypted.** Don't store auth tokens or
|
|
89
|
-
regulated data in any of these layers without adding your own encryption
|
|
90
|
-
review comments if you see it happening.
|
|
91
|
-
|
|
92
|
-
## React usage
|
|
93
|
-
|
|
94
|
-
`useObserver` has two modes
|
|
95
|
-
|
|
96
|
-
```tsx
|
|
97
|
-
// Auto-discovery: re-runs when any state path touched during the callback changes
|
|
98
|
-
useObserver(() => { console.debug('counter:', state.counter) }, state.counter)
|
|
99
|
-
|
|
100
|
-
// Explicit deps: only re-runs when the listed paths change
|
|
101
|
-
useObserver(() => { console.debug('user:', state.user) }, [state.user])
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
`useObserver` is a thin bridge onto `observer`
|
|
105
|
-
above for any path passed in string form.
|
|
106
|
-
|
|
107
|
-
## Cross-platform code
|
|
108
|
-
|
|
109
|
-
Before calling `idb`, `sqlite`, or `devtools`, or before relying on `store`/`session` durability,
|
|
110
|
-
check `memorio.getCapabilities()` rather than branching on `memorio.isNode()`/`isBrowser()` alone
|
|
111
|
-
|
|
112
|
-
`localStorage`, some don't). Generated code that assumes "browser == has IndexedDB" or
|
|
113
|
-
"Node == no persistence at all" will be wrong on edge runtimes.
|
|
114
|
-
|
|
115
|
-
## Testing
|
|
116
|
-
|
|
117
|
-
When testing `memory` lifecycle behavior (supersession, TTL, confidence), assert on the *history*
|
|
118
|
-
being preserved, not just the current `recall()` value
|
|
119
|
-
not overwrite, and a test that only checks the latest value won't catch a regression that
|
|
120
|
-
silently starts overwriting instead.
|
|
121
|
-
|
|
122
|
-
## Related examples
|
|
123
|
-
|
|
124
|
-
See `examples/` in this repo for runnable reference implementations:
|
|
125
|
-
`multi-tenant-context.ts`, `react-observer.tsx`, `semantic-memory.ts`,
|
|
126
|
-
`sqlite-batched-writes.ts`, and `cross-platform-guards.ts`.
|
|
1
|
+
# AGENTS.md - working with `memorio`
|
|
2
|
+
|
|
3
|
+
Operational conventions for AI coding agents working in a repository that depends on `memorio`.
|
|
4
|
+
See `README.md` and `llms.txt` for the full API. This file is decision rules: what to reach for,
|
|
5
|
+
when, and the specific footguns this library's own docs flag.
|
|
6
|
+
|
|
7
|
+
## Read this before generating any `memorio` code
|
|
8
|
+
|
|
9
|
+
`memorio`'s own `llms.txt` contains an explicit unresolved discrepancy:
|
|
10
|
+
|
|
11
|
+
> **Locking - VERIFY BEFORE PUBLISHING:** one source describes per-key locking
|
|
12
|
+
> (`state.config.lock()` freezes only `config`); another describes global locking
|
|
13
|
+
> (`state.lock()` / `state.unlock()` freezing everything). Do not generate code against this
|
|
14
|
+
> section until it's resolved against the real source.
|
|
15
|
+
|
|
16
|
+
**Do not write or suggest `.lock()` / `.unlock()` calls with a confident claim about scope**
|
|
17
|
+
(per-key vs. global) until you've confirmed the actual signature against the installed
|
|
18
|
+
package's type definitions or source - `node_modules/memorio/dist/*.d.ts` - in the target repo.
|
|
19
|
+
If you can't confirm it, say so explicitly rather than picking one behavior and presenting it
|
|
20
|
+
as fact.
|
|
21
|
+
|
|
22
|
+
## Choosing a layer
|
|
23
|
+
|
|
24
|
+
Don't default to `state` for everything just because it's the one-liner in the README. Walk the
|
|
25
|
+
decision tree from the README's ["Which layer should I use"](./README.md#which-layer-should-i-use)
|
|
26
|
+
section, and in particular:
|
|
27
|
+
|
|
28
|
+
| If the data is... | Use | Not |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| UI-reactive, doesn't need to survive reload | `state` | `store` (unnecessary persistence) |
|
|
31
|
+
| Small, must survive reload, any tab | `store` | `idb` (overkill for simple k/v) |
|
|
32
|
+
| Must survive reload, this tab only | `session` | `store` (wrong scope) |
|
|
33
|
+
| Relational, needs joins/SQL | `sqlite` | `idb` (no query language) |
|
|
34
|
+
| Structured, needs confidence/TTL/source/history | `memory` | `state`/`store` (no lifecycle semantics) |
|
|
35
|
+
| Large or structured, browser-only | `idb` | `store` (size/shape limits) |
|
|
36
|
+
|
|
37
|
+
`sqlite` and `memory` answer different questions - "what data do I have" vs. "what does the app
|
|
38
|
+
believe, and how sure is it." Don't reach for `memory` just because a value happens to come from
|
|
39
|
+
an LLM; if it doesn't need confidence scoring, TTL, or supersession history, plain `state`/`store`
|
|
40
|
+
is simpler and correct.
|
|
41
|
+
|
|
42
|
+
## Server-side and multi-request code - read this first
|
|
43
|
+
|
|
44
|
+
**`state` is a shared global namespace by default.** A value set in one request handler is
|
|
45
|
+
visible to every other read of `state` in the same process. There is no automatic per-request
|
|
46
|
+
or per-tab isolation.
|
|
47
|
+
|
|
48
|
+
Before generating any server-side code (API route, edge function, worker) that could handle more
|
|
49
|
+
than one user or request in the same process:
|
|
50
|
+
|
|
51
|
+
1. Create an explicit context per request/tenant: `const ctx = memorio.createContext(id)`, then
|
|
52
|
+
read/write via `ctx.state`, never the bare global `state`.
|
|
53
|
+
2. **Generate the context ID from trusted server-side data** (authenticated user id, request-scoped
|
|
54
|
+
token) - never directly from client-controlled input. Contexts are a key-prefix convention, not
|
|
55
|
+
a hard boundary, so a spoofable ID is a real collision risk, not just a naming concern.
|
|
56
|
+
3. Treat context isolation as *organizational*, not a security boundary. It does not replace
|
|
57
|
+
authorization checks at the backend layer - never use it as the only thing standing between
|
|
58
|
+
one tenant's data and another's.
|
|
59
|
+
|
|
60
|
+
If the code you're generating is client-side (a single browser tab, one user), bare `state` is
|
|
61
|
+
fine - this concern is specific to shared-process server/edge code.
|
|
62
|
+
|
|
63
|
+
## Known rough edges - don't paper over these in generated code
|
|
64
|
+
|
|
65
|
+
- **`store.quota()` returns `[0, 0]` for the `localStorage` backend** - it's a placeholder, not a
|
|
66
|
+
real reading. Don't generate capacity-check logic that branches on its result for `store`.
|
|
67
|
+
It may be meaningful for `idb`, but confirm before relying on it there too.
|
|
68
|
+
- **`idb` is disabled outright in Node.js/Deno** (calls warn and no-op). Any code that might run
|
|
69
|
+
outside a guaranteed browser context must guard: `if (idb.db.support())` or check
|
|
70
|
+
`memorio.getCapabilities().hasIndexedDB` - don't rely on the no-op warning alone reaching a log
|
|
71
|
+
anyone will see.
|
|
72
|
+
- **`sqlite` persistence serializes the entire database on every flush** - not incremental. Never
|
|
73
|
+
generate code that calls a persisting write inside a loop; batch writes in one transaction/run
|
|
74
|
+
and persist once after the batch, per the README's guidance.
|
|
75
|
+
- **`observer('state.some.path', cb)` paths are plain strings, unchecked against `state`'s actual
|
|
76
|
+
shape.** A typo or a later rename fails *silently* - the observer just never fires again. Prefer
|
|
77
|
+
`memorio.typed<T>()` + `registerSchema()` for anything you'd hate to have silently stop working,
|
|
78
|
+
and consider `memorio.pathExists('state.some.path')` as a startup sanity check for
|
|
79
|
+
observer-heavy code.
|
|
80
|
+
- **`memory.context()` is rule-based (tags/type/confidence/recency), not embedding-based.** Don't
|
|
81
|
+
imply semantic/meaning-based retrieval in comments or docs you generate - if the task genuinely
|
|
82
|
+
needs free-text similarity search, pair `memorio.memory` (for lifecycle: confidence, TTL,
|
|
83
|
+
supersession) with a separate embedding store, don't fake it with `context()` alone.
|
|
84
|
+
- **`memorio.logger` records the literal value written**, including tokens or PII, in
|
|
85
|
+
`getHistory()` / `exportLogs()`. Never enable it unconditionally on a production path that
|
|
86
|
+
touches sensitive data, and never wire `exportLogs()` output to analytics or error reporters
|
|
87
|
+
without redaction first.
|
|
88
|
+
- **Nothing in `store`, `session`, `idb`, or `memory` is encrypted.** Don't store auth tokens or
|
|
89
|
+
regulated data in any of these layers without adding your own encryption - flag it in code
|
|
90
|
+
review comments if you see it happening.
|
|
91
|
+
|
|
92
|
+
## React usage
|
|
93
|
+
|
|
94
|
+
`useObserver` has two modes - pick deliberately, don't mix them by accident:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
// Auto-discovery: re-runs when any state path touched during the callback changes
|
|
98
|
+
useObserver(() => { console.debug('counter:', state.counter) }, state.counter)
|
|
99
|
+
|
|
100
|
+
// Explicit deps: only re-runs when the listed paths change
|
|
101
|
+
useObserver(() => { console.debug('user:', state.user) }, [state.user])
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`useObserver` is a thin bridge onto `observer` - it inherits the "unchecked path string" caveat
|
|
105
|
+
above for any path passed in string form.
|
|
106
|
+
|
|
107
|
+
## Cross-platform code
|
|
108
|
+
|
|
109
|
+
Before calling `idb`, `sqlite`, or `devtools`, or before relying on `store`/`session` durability,
|
|
110
|
+
check `memorio.getCapabilities()` rather than branching on `memorio.isNode()`/`isBrowser()` alone
|
|
111
|
+
- capabilities can differ inside a single platform category (e.g. some edge runtimes expose
|
|
112
|
+
`localStorage`, some don't). Generated code that assumes "browser == has IndexedDB" or
|
|
113
|
+
"Node == no persistence at all" will be wrong on edge runtimes.
|
|
114
|
+
|
|
115
|
+
## Testing
|
|
116
|
+
|
|
117
|
+
When testing `memory` lifecycle behavior (supersession, TTL, confidence), assert on the *history*
|
|
118
|
+
being preserved, not just the current `recall()` value - `update()` is documented to supersede,
|
|
119
|
+
not overwrite, and a test that only checks the latest value won't catch a regression that
|
|
120
|
+
silently starts overwriting instead.
|
|
121
|
+
|
|
122
|
+
## Related examples
|
|
123
|
+
|
|
124
|
+
See `examples/` in this repo for runnable reference implementations:
|
|
125
|
+
`multi-tenant-context.ts`, `react-observer.tsx`, `semantic-memory.ts`,
|
|
126
|
+
`sqlite-batched-writes.ts`, and `cross-platform-guards.ts`.
|