@dungle-scrubs/hippo 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +439 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +559 -0
- package/dist/cli.js.map +1 -0
- package/dist/db.d.ts +45 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +80 -0
- package/dist/db.js.map +1 -0
- package/dist/extractor.d.ts +23 -0
- package/dist/extractor.d.ts.map +1 -0
- package/dist/extractor.js +121 -0
- package/dist/extractor.js.map +1 -0
- package/dist/hash.d.ts +11 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +14 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/embedding.d.ts +27 -0
- package/dist/providers/embedding.d.ts.map +1 -0
- package/dist/providers/embedding.js +41 -0
- package/dist/providers/embedding.js.map +1 -0
- package/dist/providers/llm.d.ts +29 -0
- package/dist/providers/llm.d.ts.map +1 -0
- package/dist/providers/llm.js +74 -0
- package/dist/providers/llm.js.map +1 -0
- package/dist/schema.d.ts +20 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +78 -0
- package/dist/schema.js.map +1 -0
- package/dist/server/config.d.ts +38 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +71 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/index.d.ts +13 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +372 -0
- package/dist/server/index.js.map +1 -0
- package/dist/similarity.d.ts +41 -0
- package/dist/similarity.d.ts.map +1 -0
- package/dist/similarity.js +70 -0
- package/dist/similarity.js.map +1 -0
- package/dist/strength.d.ts +59 -0
- package/dist/strength.d.ts.map +1 -0
- package/dist/strength.js +76 -0
- package/dist/strength.js.map +1 -0
- package/dist/tools/append-memory-block.d.ts +22 -0
- package/dist/tools/append-memory-block.d.ts.map +1 -0
- package/dist/tools/append-memory-block.js +45 -0
- package/dist/tools/append-memory-block.js.map +1 -0
- package/dist/tools/forget-memory.d.ts +31 -0
- package/dist/tools/forget-memory.d.ts.map +1 -0
- package/dist/tools/forget-memory.js +77 -0
- package/dist/tools/forget-memory.js.map +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/recall-conversation.d.ts +21 -0
- package/dist/tools/recall-conversation.d.ts.map +1 -0
- package/dist/tools/recall-conversation.js +93 -0
- package/dist/tools/recall-conversation.js.map +1 -0
- package/dist/tools/recall-memories.d.ts +29 -0
- package/dist/tools/recall-memories.d.ts.map +1 -0
- package/dist/tools/recall-memories.js +106 -0
- package/dist/tools/recall-memories.js.map +1 -0
- package/dist/tools/recall-memory-block.d.ts +21 -0
- package/dist/tools/recall-memory-block.d.ts.map +1 -0
- package/dist/tools/recall-memory-block.js +36 -0
- package/dist/tools/recall-memory-block.js.map +1 -0
- package/dist/tools/remember-facts.d.ts +30 -0
- package/dist/tools/remember-facts.d.ts.map +1 -0
- package/dist/tools/remember-facts.js +235 -0
- package/dist/tools/remember-facts.js.map +1 -0
- package/dist/tools/replace-memory-block.d.ts +25 -0
- package/dist/tools/replace-memory-block.d.ts.map +1 -0
- package/dist/tools/replace-memory-block.js +69 -0
- package/dist/tools/replace-memory-block.js.map +1 -0
- package/dist/tools/store-memory.d.ts +27 -0
- package/dist/tools/store-memory.d.ts.map +1 -0
- package/dist/tools/store-memory.js +129 -0
- package/dist/tools/store-memory.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ulid.d.ts +13 -0
- package/dist/ulid.d.ts.map +1 -0
- package/dist/ulid.js +39 -0
- package/dist/ulid.js.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Kevin Frilot
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
# Hippo
|
|
2
|
+
|
|
3
|
+
Persistent memory for AI agents. Give your agent the ability to
|
|
4
|
+
learn facts, store experiences, recall semantically, and forget
|
|
5
|
+
on command — backed by SQLite, with no external services.
|
|
6
|
+
|
|
7
|
+
## Three ways to use it
|
|
8
|
+
|
|
9
|
+
| Mode | What | When |
|
|
10
|
+
|------|------|------|
|
|
11
|
+
| **Library** | `createHippoTools(opts)` returns `AgentTool[]` | You're building on marrow / pi-agent-core |
|
|
12
|
+
| **MCP server** | `hippo-server` binary, HTTP/SSE or STDIO | Any MCP-compatible client (Claude, Cursor, etc.) |
|
|
13
|
+
| **CLI** | `hippo` binary for inspection and management | Database admin, debugging, backup/restore |
|
|
14
|
+
|
|
15
|
+
All three share the same SQLite storage, strength model, and
|
|
16
|
+
conflict resolution. The library and MCP server provide all 8
|
|
17
|
+
memory tools. The CLI provides read/write database access without
|
|
18
|
+
embedding or LLM calls.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pnpm add @dungle-scrubs/hippo
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Peer dependencies: `better-sqlite3`, `@mariozechner/pi-agent-core`,
|
|
27
|
+
`@mariozechner/pi-ai`.
|
|
28
|
+
|
|
29
|
+
## Quick start — Library
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import Database from "better-sqlite3";
|
|
33
|
+
import { createHippoTools } from "@dungle-scrubs/hippo";
|
|
34
|
+
|
|
35
|
+
const db = new Database("agent.db");
|
|
36
|
+
|
|
37
|
+
const tools = createHippoTools({
|
|
38
|
+
db,
|
|
39
|
+
agentId: "my-agent",
|
|
40
|
+
embed: async (text) => {
|
|
41
|
+
// Your embedding function → Float32Array
|
|
42
|
+
return callEmbeddingApi(text);
|
|
43
|
+
},
|
|
44
|
+
llm: {
|
|
45
|
+
complete: async (messages, systemPrompt) => {
|
|
46
|
+
return callLlm(messages, systemPrompt);
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Pass to your agent framework
|
|
52
|
+
agent.addTools(tools);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`createHippoTools` initializes the schema (idempotent) and returns
|
|
56
|
+
7 tools. Pass `messagesTable: "messages"` to get an 8th tool that
|
|
57
|
+
searches conversation history via FTS5.
|
|
58
|
+
|
|
59
|
+
### Built-in providers
|
|
60
|
+
|
|
61
|
+
Don't want to wire up embedding and LLM functions yourself? Hippo
|
|
62
|
+
ships OpenAI-compatible providers that work with any `/v1/embeddings`
|
|
63
|
+
or `/v1/chat/completions` endpoint (OpenAI, OpenRouter, Ollama,
|
|
64
|
+
vLLM, etc.):
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import Database from "better-sqlite3";
|
|
68
|
+
import {
|
|
69
|
+
createHippoTools,
|
|
70
|
+
createEmbeddingProvider,
|
|
71
|
+
createLlmProvider,
|
|
72
|
+
} from "@dungle-scrubs/hippo";
|
|
73
|
+
|
|
74
|
+
const db = new Database("agent.db");
|
|
75
|
+
|
|
76
|
+
const tools = createHippoTools({
|
|
77
|
+
db,
|
|
78
|
+
agentId: "my-agent",
|
|
79
|
+
embed: createEmbeddingProvider({
|
|
80
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
81
|
+
baseUrl: "https://api.openai.com/v1",
|
|
82
|
+
model: "text-embedding-3-small",
|
|
83
|
+
dimensions: 1536, // optional
|
|
84
|
+
}),
|
|
85
|
+
llm: createLlmProvider({
|
|
86
|
+
apiKey: process.env.OPENROUTER_API_KEY!,
|
|
87
|
+
baseUrl: "https://openrouter.ai/api/v1",
|
|
88
|
+
model: "google/gemini-flash-2.0",
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Embedding model safety
|
|
94
|
+
|
|
95
|
+
Call `verifyEmbeddingModel(db, "text-embedding-3-small")` after
|
|
96
|
+
`initSchema` to lock the database to a specific embedding model.
|
|
97
|
+
First call stores the model name. Subsequent calls throw if the
|
|
98
|
+
model doesn't match — prevents mixing incompatible vector spaces.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { initSchema, verifyEmbeddingModel } from "@dungle-scrubs/hippo";
|
|
102
|
+
|
|
103
|
+
initSchema(db);
|
|
104
|
+
verifyEmbeddingModel(db, "text-embedding-3-small");
|
|
105
|
+
// Later, with a different model:
|
|
106
|
+
verifyEmbeddingModel(db, "voyage-3"); // throws!
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Quick start — MCP server
|
|
110
|
+
|
|
111
|
+
The MCP server handles embedding and LLM calls internally. Clients
|
|
112
|
+
send text; hippo vectorizes and stores. Every tool call takes an
|
|
113
|
+
`agent_id` parameter for multi-agent support on a shared database.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Required
|
|
117
|
+
export HIPPO_DB=./agent.db
|
|
118
|
+
export HIPPO_EMBED_KEY=sk-...
|
|
119
|
+
export HIPPO_LLM_KEY=sk-...
|
|
120
|
+
|
|
121
|
+
# Start HTTP/SSE server (default)
|
|
122
|
+
hippo-server
|
|
123
|
+
|
|
124
|
+
# Or STDIO for single-client piping
|
|
125
|
+
HIPPO_TRANSPORT=stdio hippo-server
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Server environment variables
|
|
129
|
+
|
|
130
|
+
| Variable | Required | Default |
|
|
131
|
+
|----------|----------|---------|
|
|
132
|
+
| `HIPPO_DB` | Yes | — |
|
|
133
|
+
| `HIPPO_EMBED_KEY` | Yes | — |
|
|
134
|
+
| `HIPPO_LLM_KEY` | Yes | — |
|
|
135
|
+
| `HIPPO_TRANSPORT` | No | `http` |
|
|
136
|
+
| `HIPPO_PORT` | No | `3100` |
|
|
137
|
+
| `HIPPO_EMBED_URL` | No | `https://api.openai.com/v1` |
|
|
138
|
+
| `HIPPO_EMBED_MODEL` | No | `text-embedding-3-small` |
|
|
139
|
+
| `HIPPO_EMBED_DIMENSIONS` | No | (model default) |
|
|
140
|
+
| `HIPPO_LLM_URL` | No | `https://openrouter.ai/api/v1` |
|
|
141
|
+
| `HIPPO_LLM_MODEL` | No | `google/gemini-flash-2.0` |
|
|
142
|
+
|
|
143
|
+
### HTTP endpoints
|
|
144
|
+
|
|
145
|
+
| Method | Path | Purpose |
|
|
146
|
+
|--------|------|---------|
|
|
147
|
+
| `GET` | `/sse` | Open SSE connection (returns `sessionId`) |
|
|
148
|
+
| `POST` | `/messages?sessionId=<id>` | Send MCP messages |
|
|
149
|
+
| `GET` | `/health` | Health check (`{"status": "ok"}`) |
|
|
150
|
+
|
|
151
|
+
## Quick start — CLI
|
|
152
|
+
|
|
153
|
+
The CLI inspects and manages hippo databases without embedding or
|
|
154
|
+
LLM access. For semantic operations, use the library or MCP server.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Set once, or pass --db <path> to every command
|
|
158
|
+
export HIPPO_DB=./agent.db
|
|
159
|
+
|
|
160
|
+
# Initialize schema (idempotent)
|
|
161
|
+
hippo init
|
|
162
|
+
|
|
163
|
+
# Overview
|
|
164
|
+
hippo stats
|
|
165
|
+
hippo agents
|
|
166
|
+
|
|
167
|
+
# Browse data
|
|
168
|
+
hippo chunks my-agent
|
|
169
|
+
hippo chunks my-agent --kind fact --limit 20
|
|
170
|
+
hippo blocks my-agent
|
|
171
|
+
hippo block my-agent persona
|
|
172
|
+
|
|
173
|
+
# Text search (case-insensitive, across all agents)
|
|
174
|
+
hippo search "redux" --kind fact
|
|
175
|
+
|
|
176
|
+
# Maintenance
|
|
177
|
+
hippo delete CHUNK_ID_1 CHUNK_ID_2 --force
|
|
178
|
+
hippo purge --force
|
|
179
|
+
hippo purge --agent my-agent --before 2025-01-01 --force
|
|
180
|
+
|
|
181
|
+
# Backup and restore
|
|
182
|
+
hippo export my-agent > backup.json
|
|
183
|
+
hippo import backup.json
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
All commands support `--json` for machine-readable output.
|
|
187
|
+
|
|
188
|
+
### CLI commands
|
|
189
|
+
|
|
190
|
+
| Command | What it does |
|
|
191
|
+
|---------|-------------|
|
|
192
|
+
| `init` | Create tables and indexes (idempotent) |
|
|
193
|
+
| `stats` | Chunk counts, block counts, agent count, file size |
|
|
194
|
+
| `agents` | List all agent IDs with chunk counts |
|
|
195
|
+
| `chunks <agent>` | List chunks with filters (`--kind`, `--superseded`, `--limit`) |
|
|
196
|
+
| `blocks <agent>` | List memory blocks with sizes |
|
|
197
|
+
| `block <agent> <key>` | Get contents of a named block |
|
|
198
|
+
| `search <text>` | Case-insensitive LIKE search across chunks |
|
|
199
|
+
| `delete <ids...>` | Hard delete by ID, resurrects superseded chunks |
|
|
200
|
+
| `purge` | Remove superseded chunks (`--agent`, `--before` filters) |
|
|
201
|
+
| `export <agent>` | Export all data as JSON (embeddings as base64) |
|
|
202
|
+
| `import <file>` | Import from JSON, skip duplicate IDs |
|
|
203
|
+
|
|
204
|
+
## Tools
|
|
205
|
+
|
|
206
|
+
### Write
|
|
207
|
+
|
|
208
|
+
| Tool | What it does |
|
|
209
|
+
|------|-------------|
|
|
210
|
+
| `remember_facts` | Extract facts from text, rate intensity, detect duplicates and contradictions, store or update |
|
|
211
|
+
| `store_memory` | Store raw content (docs, decisions, experiences) with content-hash dedup |
|
|
212
|
+
| `append_memory_block` | Append text to a named block (creates if missing) |
|
|
213
|
+
| `replace_memory_block` | Find/replace text in a named block (replaces all occurrences) |
|
|
214
|
+
| `forget_memory` | Semantic match → hard delete. No audit trail. |
|
|
215
|
+
|
|
216
|
+
### Read
|
|
217
|
+
|
|
218
|
+
| Tool | What it does |
|
|
219
|
+
|------|-------------|
|
|
220
|
+
| `recall_memories` | Semantic search across facts and memories, ranked by relevance × strength × recency |
|
|
221
|
+
| `recall_memory_block` | Get contents of a named block (null if missing) |
|
|
222
|
+
| `recall_conversation` | Full-text search over past messages (FTS5) |
|
|
223
|
+
|
|
224
|
+
## Key concepts
|
|
225
|
+
|
|
226
|
+
### Facts vs memories
|
|
227
|
+
|
|
228
|
+
Both live in the same `chunks` table, distinguished by a `kind` column.
|
|
229
|
+
|
|
230
|
+
**Facts** are atomic claims that can conflict. "User lives in
|
|
231
|
+
Berlin" can be superseded by "User lives in Bangkok." They go
|
|
232
|
+
through extraction, embedding, and conflict resolution.
|
|
233
|
+
|
|
234
|
+
**Memories** are raw content — experiences, documents, decisions.
|
|
235
|
+
They can't conflict. Verbatim duplicates are strengthened, not
|
|
236
|
+
re-inserted.
|
|
237
|
+
|
|
238
|
+
### Strength and decay
|
|
239
|
+
|
|
240
|
+
Every memory decays over time unless actively used. Two forces
|
|
241
|
+
interact:
|
|
242
|
+
|
|
243
|
+
**Running intensity** — a moving average across encounters.
|
|
244
|
+
A single emotional outburst doesn't cement a memory; sustained
|
|
245
|
+
intensity over multiple encounters does. Early readings have
|
|
246
|
+
high influence, but the average stabilizes as data accumulates.
|
|
247
|
+
|
|
248
|
+
**Decay resistance** — built by access frequency. A memory
|
|
249
|
+
recalled 50 times decays far slower than one recalled once.
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
effective_strength = intensity × e^(-λ / resistance × hours)
|
|
253
|
+
resistance = 1 + log(1 + access_count) × 0.3
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
| Access count | Decay resistance | Half-life |
|
|
257
|
+
|--------------|-----------------|-----------|
|
|
258
|
+
| 0 | 1.0 | ~29 days |
|
|
259
|
+
| 5 | 1.54 | ~44 days |
|
|
260
|
+
| 20 | 1.91 | ~55 days |
|
|
261
|
+
| 100 | 2.38 | ~69 days |
|
|
262
|
+
|
|
263
|
+
Memories below 5% effective strength are excluded from search
|
|
264
|
+
results — effectively forgotten through disuse.
|
|
265
|
+
|
|
266
|
+
### Conflict resolution
|
|
267
|
+
|
|
268
|
+
When `remember_facts` stores a new fact, it checks existing
|
|
269
|
+
facts by cosine similarity (top 5 candidates):
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
> 0.93 → auto-classify DUPLICATE, strengthen existing
|
|
273
|
+
0.78–0.93 → LLM tiebreaker (one cheap call)
|
|
274
|
+
< 0.78 → auto-classify NEW, insert
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
The LLM returns one of three verdicts: **DUPLICATE** (same info,
|
|
278
|
+
different words), **SUPERSEDES** (same topic, new value), or
|
|
279
|
+
**DISTINCT** (related but both true).
|
|
280
|
+
|
|
281
|
+
Facts extracted from the same text have intra-batch visibility —
|
|
282
|
+
each fact sees the results of previously processed facts in the
|
|
283
|
+
same call, preventing duplicate insertions within a batch.
|
|
284
|
+
|
|
285
|
+
### Search scoring
|
|
286
|
+
|
|
287
|
+
`recall_memories` ranks results by a weighted composite:
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
score = 0.6 × cosine_similarity
|
|
291
|
+
+ 0.3 × effective_strength
|
|
292
|
+
+ 0.1 × recency_score
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Recency decays exponentially: ~0.97 at 3 days, ~0.74 at 30 days,
|
|
296
|
+
~0.03 at 1 year.
|
|
297
|
+
|
|
298
|
+
Accessed chunks get a small retrieval boost (+0.02 to intensity),
|
|
299
|
+
so frequently recalled memories stay strong.
|
|
300
|
+
|
|
301
|
+
### Forgetting
|
|
302
|
+
|
|
303
|
+
`forget_memory` performs a hard delete. No soft deletes, no audit
|
|
304
|
+
trail. When a deleted chunk had superseded another chunk, the
|
|
305
|
+
superseded chunk is resurrected (its `superseded_by` reference is
|
|
306
|
+
cleared).
|
|
307
|
+
|
|
308
|
+
Memory blocks are not touched by `forget_memory` — use
|
|
309
|
+
`replace_memory_block` separately if needed.
|
|
310
|
+
|
|
311
|
+
## Configuration
|
|
312
|
+
|
|
313
|
+
### Library options
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
interface HippoOptions {
|
|
317
|
+
db: Database; // better-sqlite3 handle
|
|
318
|
+
agentId: string; // namespace for multi-agent isolation
|
|
319
|
+
embed: EmbedFn; // (text, signal?) => Float32Array
|
|
320
|
+
llm: LlmClient; // { complete(messages, systemPrompt, signal?) }
|
|
321
|
+
messagesTable?: string; // enables recall_conversation
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**`agentId`** — all chunks and blocks are scoped to this ID.
|
|
326
|
+
Multiple agents can share one database without interference.
|
|
327
|
+
|
|
328
|
+
**`embed`** — you provide the embedding function. Hippo stores
|
|
329
|
+
the resulting `Float32Array` as a BLOB and does brute-force
|
|
330
|
+
cosine similarity at query time. Any embedding model works;
|
|
331
|
+
dimensions don't matter as long as they're consistent.
|
|
332
|
+
|
|
333
|
+
**`llm`** — used only by `remember_facts` for extraction and
|
|
334
|
+
conflict classification. A cheap, fast model is ideal. Most
|
|
335
|
+
tools make zero LLM calls.
|
|
336
|
+
|
|
337
|
+
**`messagesTable`** — if your agent writes messages to a table,
|
|
338
|
+
hippo can search it with FTS5. You own the table and FTS index;
|
|
339
|
+
hippo just reads from it. Omit this to exclude
|
|
340
|
+
`recall_conversation` from the tool set.
|
|
341
|
+
|
|
342
|
+
### Embedding provider options
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
interface EmbeddingProviderConfig {
|
|
346
|
+
apiKey: string; // Bearer token
|
|
347
|
+
baseUrl: string; // e.g. "https://api.openai.com/v1"
|
|
348
|
+
model: string; // e.g. "text-embedding-3-small"
|
|
349
|
+
dimensions?: number; // optional, model-dependent
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### LLM provider options
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
interface LlmProviderConfig {
|
|
357
|
+
apiKey: string; // Bearer token
|
|
358
|
+
baseUrl: string; // e.g. "https://openrouter.ai/api/v1"
|
|
359
|
+
model: string; // e.g. "google/gemini-flash-2.0"
|
|
360
|
+
maxTokens?: number; // default: 2048
|
|
361
|
+
temperature?: number; // default: 0
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## LLM and embedding costs
|
|
366
|
+
|
|
367
|
+
| Tool | LLM calls | Embed calls |
|
|
368
|
+
|------|-----------|-------------|
|
|
369
|
+
| `remember_facts` | 1–2 | N (per extracted fact) |
|
|
370
|
+
| `store_memory` | 0 | 1 |
|
|
371
|
+
| `recall_memories` | 0 | 1 |
|
|
372
|
+
| `forget_memory` | 0 | 1 |
|
|
373
|
+
| `recall_memory_block` | 0 | 0 |
|
|
374
|
+
| `replace_memory_block` | 0 | 0 |
|
|
375
|
+
| `append_memory_block` | 0 | 0 |
|
|
376
|
+
| `recall_conversation` | 0 | 0 |
|
|
377
|
+
|
|
378
|
+
The second LLM call in `remember_facts` only fires when a
|
|
379
|
+
candidate falls in the ambiguous 0.78–0.93 similarity band.
|
|
380
|
+
Most facts are clearly new or clearly duplicate and skip it.
|
|
381
|
+
|
|
382
|
+
## Storage
|
|
383
|
+
|
|
384
|
+
SQLite via better-sqlite3. Schema is created automatically on
|
|
385
|
+
first call. WAL mode and 5-second busy timeout are set on every
|
|
386
|
+
connection.
|
|
387
|
+
|
|
388
|
+
```
|
|
389
|
+
chunks — facts and memories with embeddings
|
|
390
|
+
memory_blocks — key-value text blocks (persona, objectives, etc.)
|
|
391
|
+
hippo_meta — embedding model tracking
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Brute-force cosine similarity is viable up to ~10k chunks per
|
|
395
|
+
agent. Beyond that, pre-filter by recency or tags. Past 50k,
|
|
396
|
+
consider migrating to sqlite-vec.
|
|
397
|
+
|
|
398
|
+
## Exports
|
|
399
|
+
|
|
400
|
+
The library exports both the tool factory and all building blocks:
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
// Main API
|
|
404
|
+
export { createHippoTools } from "@dungle-scrubs/hippo";
|
|
405
|
+
|
|
406
|
+
// Built-in providers
|
|
407
|
+
export { createEmbeddingProvider } from "@dungle-scrubs/hippo";
|
|
408
|
+
export { createLlmProvider } from "@dungle-scrubs/hippo";
|
|
409
|
+
|
|
410
|
+
// Schema utilities
|
|
411
|
+
export { initSchema, verifyEmbeddingModel } from "@dungle-scrubs/hippo";
|
|
412
|
+
|
|
413
|
+
// Types
|
|
414
|
+
export type {
|
|
415
|
+
Chunk, ChunkKind, EmbedFn, HippoOptions,
|
|
416
|
+
LlmClient, MemoryBlock, RememberFactAction,
|
|
417
|
+
RememberFactsResult, SearchResult,
|
|
418
|
+
EmbeddingProviderConfig, LlmProviderConfig,
|
|
419
|
+
} from "@dungle-scrubs/hippo";
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Development
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
pnpm install
|
|
426
|
+
just ci # build + check + test
|
|
427
|
+
|
|
428
|
+
just build # tsc → dist/
|
|
429
|
+
just test # vitest run (199 tests)
|
|
430
|
+
just test-watch # vitest watch mode
|
|
431
|
+
just typecheck # tsc --noEmit
|
|
432
|
+
just check # biome lint + format
|
|
433
|
+
just fix # auto-fix lint and format
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Requirements
|
|
437
|
+
|
|
438
|
+
- Node ≥ 22
|
|
439
|
+
- pnpm
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|