wolbarg 0.5.1 → 0.5.3

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/CHANGELOG.md CHANGED
@@ -5,6 +5,42 @@ All notable changes to this project are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [0.5.3] — 2026-07-20
9
+
10
+ ### Added
11
+
12
+ - **Official framework adapters (`@1.0.0`)** — `@wolbarg/openai`, `@wolbarg/langchain`, `@wolbarg/llamaindex`, `@wolbarg/mastra` (alongside existing `@wolbarg/vercel-ai`)
13
+ - Docs + runnable examples under `examples/adapters/*` and [Integrations](https://wolbarg.com/docs/integrations)
14
+
15
+ ### Compatibility
16
+
17
+ - Additive only. Core API unchanged from **0.5.2**. Adapter packages peer-depend on `wolbarg >= 0.5.3`.
18
+
19
+ ## [0.5.2] — 2026-07-19
20
+
21
+ ### Added
22
+
23
+ - **`rememberFromMessages()` (experimental)** — conversation → memory bridge with `mode: "raw"` (default, no LLM) and optional `mode: "extract"` via configured `llm`
24
+ - **Vercel AI SDK adapter example** — `examples/adapters/vercel-ai/` (now uses official `@wolbarg/vercel-ai` middleware)
25
+ - **Companion package `@wolbarg/vercel-ai`** — Language Model Middleware (`wolbargMiddleware` + `wrapLanguageModel`) for automatic recall / remember (published separately under `packages/vercel-ai/`)
26
+
27
+ ### Compatibility
28
+
29
+ - Additive only. Omit the new method and behavior matches **0.5.1**. Experimental API may change before 1.0 — pin versions if you depend on it.
30
+ - Core `wolbarg` remains framework-agnostic; AI SDK types live only in `@wolbarg/vercel-ai`.
31
+ - `@wolbarg/vercel-ai@1` requires **AI SDK v7+** (`ai@^7`). Upgrade from AI SDK v4 before adopting the middleware.
32
+
33
+ ## [0.5.1] — 2026-07-19
34
+
35
+
36
+ ### Fixed
37
+
38
+ - **SQLite vec0 rowid binding on Linux** — bind `memory_rowid` as `BigInt` for `node:sqlite` + sqlite-vec so CI / Linux inserts and KNN search do not fail on integer PK binds
39
+
40
+ ### Compatibility
41
+
42
+ - Drop-in patch for **0.5.0**. No API or schema changes.
43
+
8
44
  ## [0.5.0] — 2026-07-19
9
45
 
10
46
  ### Added
@@ -166,6 +202,7 @@ const ctx = wolbarg({
166
202
 
167
203
  - Initial npm release path (pre–modular storage / ingest)
168
204
 
205
+ [0.5.1]: https://github.com/wolbarg/wolbarg/releases/tag/v0.5.1
169
206
  [0.5.0]: https://github.com/wolbarg/wolbarg/releases/tag/v0.5.0
170
207
  [0.4.0]: https://github.com/wolbarg/wolbarg/releases/tag/v0.4.0
171
208
  [0.3.2]: https://github.com/wolbarg/wolbarg/releases/tag/v0.3.2
package/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  **Modular, provider-agnostic semantic memory for AI agents.**
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/wolbarg.svg)](https://www.npmjs.com/package/wolbarg)
8
+ [![SDK CI](https://github.com/wolbarg/wolbarg/actions/workflows/sdk-ci.yml/badge.svg?branch=main)](https://github.com/wolbarg/wolbarg/actions/workflows/sdk-ci.yml)
8
9
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
9
10
  [![Node.js](https://img.shields.io/badge/node-%3E%3D22.5-brightgreen.svg)](https://nodejs.org)
10
11
  [![Docs](https://img.shields.io/badge/docs-wolbarg.com-black)](https://wolbarg.com)
@@ -16,7 +17,7 @@ npm install wolbarg
16
17
 
17
18
  Wolbarg is **memory infrastructure**, not an agent framework. Agents call `remember()` / `recall()` (and optionally ingest, compress, subscribe, and link memories in a graph). You bring SQLite or PostgreSQL, any OpenAI-compatible embedding API, and optional peers for PDF/DOCX/OCR/Neo4j.
18
19
 
19
- **Current release: [v0.5.0](./CHANGELOG.md)** — optional graph memory (SQLite + Neo4j), `includeGraph` recall, cascade forget, graph-aware checkpoints, and [Wolbarg Studio](https://wolbarg.com/docs/observability) graph canvas.
20
+ **Current release: [v0.5.3](./CHANGELOG.md)** — official framework adapters (`@wolbarg/openai`, `@wolbarg/langchain`, `@wolbarg/llamaindex`, `@wolbarg/mastra`, `@wolbarg/vercel-ai`). Still includes experimental `rememberFromMessages()`, 0.5 graph memory (SQLite + Neo4j), `includeGraph` recall, and [Wolbarg Studio](https://wolbarg.com/docs/observability).
20
21
 
21
22
  ---
22
23
 
@@ -46,10 +47,12 @@ Wolbarg is **memory infrastructure**, not an agent framework. Agents call `remem
46
47
  - **Embedding cache** — `hash(content) + model`
47
48
  - **Dedupe / upsert** — opt-in exact / near / exact-or-near
48
49
  - **Graph memory (0.5)** — `sqliteGraph` / `neo4jGraph`, `linkMemories`, `getRelated`, `includeGraph`
50
+ - **Conversation bridge (0.5.2, experimental)** — `rememberFromMessages()` raw or LLM extract
51
+ - **Framework adapter** — official [`@wolbarg/vercel-ai`](../packages/vercel-ai/) middleware (`wrapLanguageModel`)
49
52
  - **Checkpoints / export** — file-backed SQLite snapshots (+ graph file when applicable)
50
53
  - **Telemetry** — independent event DB; Studio dashboard, Trace Explorer, graph canvas
51
54
 
52
- Docs: [Getting started](https://wolbarg.com/docs/getting-started) · [What's new in 0.5](https://wolbarg.com/docs/guides/whats-new) · [Graph memory](https://wolbarg.com/docs/graph-memory) · [Studio](https://wolbarg.com/docs/observability)
55
+ Docs: [Getting started](https://wolbarg.com/docs/getting-started) · [Vercel AI](https://wolbarg.com/docs/integrations/vercel-ai) · [rememberFromMessages](https://wolbarg.com/docs/api/remember-from-messages) · [Graph memory](https://wolbarg.com/docs/graph-memory) · [Studio](https://wolbarg.com/docs/observability)
53
56
 
54
57
  ---
55
58
 
package/dist/index.cjs CHANGED
@@ -1634,7 +1634,7 @@ var SQL = {
1634
1634
  AND k = ?
1635
1635
  `,
1636
1636
  insertEmbeddingBlob: `
1637
- INSERT INTO memory_embeddings_blob (memory_rowid, embedding) VALUES (?, ?)
1637
+ INSERT OR REPLACE INTO memory_embeddings_blob (memory_rowid, embedding) VALUES (?, ?)
1638
1638
  `,
1639
1639
  deleteEmbeddingBlob: `
1640
1640
  DELETE FROM memory_embeddings_blob WHERE memory_rowid = ?
@@ -2590,6 +2590,13 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
2590
2590
  this.deleteEmbeddingsForScope(organization);
2591
2591
  this.deleteFtsForScope(organization);
2592
2592
  const result = stmts.deleteMemoriesByOrg.run(organization);
2593
+ try {
2594
+ this.requireDb().exec(`
2595
+ DELETE FROM memory_embeddings_blob
2596
+ WHERE memory_rowid NOT IN (SELECT rowid FROM memories)
2597
+ `);
2598
+ } catch {
2599
+ }
2593
2600
  return Number(result.changes);
2594
2601
  });
2595
2602
  }
@@ -3104,7 +3111,7 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
3104
3111
  if (!stmt) {
3105
3112
  const values = Array.from({ length: n }, () => "(?, ?)").join(", ");
3106
3113
  stmt = this.requireDb().prepare(
3107
- `INSERT INTO memory_embeddings_blob (memory_rowid, embedding) VALUES ${values}`
3114
+ `INSERT OR REPLACE INTO memory_embeddings_blob (memory_rowid, embedding) VALUES ${values}`
3108
3115
  );
3109
3116
  this.batchBlobEmbStatements.set(n, stmt);
3110
3117
  }
@@ -3325,12 +3332,13 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
3325
3332
  insertEmbedding(rowid, embedding) {
3326
3333
  const stmts = this.requireStatements();
3327
3334
  if (this.vectorBackend === "sqlite-vec") {
3328
- stmts.insertEmbedding.run(rowid, this.toVectorParam(embedding));
3335
+ stmts.insertEmbedding.run(this.toVecRowid(rowid), this.toVectorParam(embedding));
3329
3336
  return;
3330
3337
  }
3331
- stmts.insertEmbeddingBlob.run(rowid, embeddingToBuffer(embedding));
3338
+ const id = Number(rowid);
3339
+ stmts.insertEmbeddingBlob.run(id, embeddingToBuffer(embedding));
3332
3340
  if (this.memoryIndex) {
3333
- this.memoryIndex.upsert(rowid, embedding);
3341
+ this.memoryIndex.upsert(id, embedding);
3334
3342
  this.memoryIndexDirty = false;
3335
3343
  } else {
3336
3344
  this.memoryIndexDirty = true;
@@ -3340,10 +3348,11 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
3340
3348
  const stmts = this.requireStatements();
3341
3349
  try {
3342
3350
  if (this.vectorBackend === "sqlite-vec" && stmts.deleteEmbedding) {
3343
- stmts.deleteEmbedding.run(rowid);
3351
+ stmts.deleteEmbedding.run(this.toVecRowid(rowid));
3344
3352
  } else if (stmts.deleteEmbeddingBlob) {
3345
- stmts.deleteEmbeddingBlob.run(rowid);
3346
- this.memoryIndex?.remove(rowid);
3353
+ const id = Number(rowid);
3354
+ stmts.deleteEmbeddingBlob.run(id);
3355
+ this.memoryIndex?.remove(id);
3347
3356
  this.memoryIndexDirty = true;
3348
3357
  }
3349
3358
  } catch {
@@ -3360,8 +3369,8 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
3360
3369
  for (let i = 0; i < rows.length; i += 1) {
3361
3370
  const row = rows[i];
3362
3371
  hits[i] = {
3363
- memoryRowid: row.memory_rowid,
3364
- distance: row.distance
3372
+ memoryRowid: Number(row.memory_rowid),
3373
+ distance: Number(row.distance)
3365
3374
  };
3366
3375
  }
3367
3376
  return hits;
@@ -3437,6 +3446,10 @@ var SqliteStorageProvider = class _SqliteStorageProvider {
3437
3446
  const buffer = embeddingToBuffer(embedding);
3438
3447
  return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
3439
3448
  }
3449
+ /** sqlite-vec vec0 PKs must be bound as BigInt under node:sqlite. */
3450
+ toVecRowid(rowid) {
3451
+ return typeof rowid === "bigint" ? rowid : BigInt(rowid);
3452
+ }
3440
3453
  describe(error) {
3441
3454
  if (error instanceof Error) {
3442
3455
  return error.message;
@@ -5165,7 +5178,7 @@ function createDatabaseProvider(config) {
5165
5178
  }
5166
5179
 
5167
5180
  // src/version.ts
5168
- var SDK_VERSION = "0.5.0";
5181
+ var SDK_VERSION = "0.5.3";
5169
5182
 
5170
5183
  // src/memory/transfer.ts
5171
5184
  var SqliteMemoryTransferProvider = class {
@@ -5291,6 +5304,96 @@ function resolvePath(p) {
5291
5304
  return path7__default.default.isAbsolute(p) ? p : path7__default.default.resolve(process.cwd(), p);
5292
5305
  }
5293
5306
 
5307
+ // src/memory/from-messages.ts
5308
+ var DEFAULT_RAW_STRATEGY = "last_user";
5309
+ function normalizeConversationMessages(messages) {
5310
+ if (!Array.isArray(messages)) {
5311
+ throw new ValidationError("messages must be an array");
5312
+ }
5313
+ if (messages.length === 0) {
5314
+ throw new ValidationError("messages must be a non-empty array");
5315
+ }
5316
+ return messages.map((message, index) => {
5317
+ if (!message || typeof message !== "object") {
5318
+ throw new ValidationError(`messages[${index}] must be an object`);
5319
+ }
5320
+ if (typeof message.role !== "string" || message.role.trim().length === 0) {
5321
+ throw new ValidationError(`messages[${index}].role must be a non-empty string`);
5322
+ }
5323
+ if (typeof message.content !== "string") {
5324
+ throw new ValidationError(`messages[${index}].content must be a string`);
5325
+ }
5326
+ return {
5327
+ role: message.role.trim(),
5328
+ content: message.content.trim()
5329
+ };
5330
+ });
5331
+ }
5332
+ function resolveRememberFromMessagesOptions(options) {
5333
+ if (!options || typeof options !== "object") {
5334
+ throw new ValidationError("options is required");
5335
+ }
5336
+ if (typeof options.agent !== "string" || options.agent.trim().length === 0) {
5337
+ throw new ValidationError("agent must be a non-empty string");
5338
+ }
5339
+ const mode = options.mode ?? "raw";
5340
+ if (mode !== "raw" && mode !== "extract") {
5341
+ throw new ValidationError('mode must be "raw" or "extract"');
5342
+ }
5343
+ const rawStrategy = options.rawStrategy ?? DEFAULT_RAW_STRATEGY;
5344
+ if (rawStrategy !== "last_user" && rawStrategy !== "all_user") {
5345
+ throw new ValidationError('rawStrategy must be "last_user" or "all_user"');
5346
+ }
5347
+ return {
5348
+ agent: options.agent.trim(),
5349
+ mode,
5350
+ rawStrategy,
5351
+ ...options.metadata !== void 0 ? { metadata: options.metadata } : {},
5352
+ ...options.dedupe !== void 0 ? { dedupe: options.dedupe } : {}
5353
+ };
5354
+ }
5355
+ function selectRawUserTexts(messages, strategy) {
5356
+ const userTexts = messages.filter((m) => m.role === "user" && m.content.length > 0).map((m) => m.content);
5357
+ if (userTexts.length === 0) {
5358
+ throw new ValidationError(
5359
+ 'no user messages with non-empty content \u2014 nothing to remember in mode "raw"'
5360
+ );
5361
+ }
5362
+ if (strategy === "last_user") {
5363
+ return [userTexts[userTexts.length - 1]];
5364
+ }
5365
+ return userTexts;
5366
+ }
5367
+ function buildExtractMessages(messages) {
5368
+ const transcript = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
5369
+ return [
5370
+ {
5371
+ role: "system",
5372
+ content: "Extract durable factual memories from the conversation. Return only atomic facts, one per line. No numbering, bullets, or commentary. If there are no facts worth storing, reply with exactly NONE."
5373
+ },
5374
+ {
5375
+ role: "user",
5376
+ content: transcript
5377
+ }
5378
+ ];
5379
+ }
5380
+ function parseExtractedFacts(llmOutput) {
5381
+ const trimmed = llmOutput.trim();
5382
+ if (trimmed.length === 0 || /^none$/i.test(trimmed)) {
5383
+ return [];
5384
+ }
5385
+ const facts = [];
5386
+ for (const line of trimmed.split(/\r?\n/)) {
5387
+ let fact = line.trim();
5388
+ if (fact.length === 0) continue;
5389
+ fact = fact.replace(/^[-*•]\s+/, "");
5390
+ fact = fact.replace(/^\d+[.)]\s+/, "");
5391
+ if (fact.length === 0 || /^none$/i.test(fact)) continue;
5392
+ facts.push(fact);
5393
+ }
5394
+ return facts;
5395
+ }
5396
+
5294
5397
  // src/memory/index.ts
5295
5398
  function toMemoryRecord(row) {
5296
5399
  return {
@@ -7739,6 +7842,81 @@ var Wolbarg = class {
7739
7842
  throw wrapOperationError("rememberBatch", error);
7740
7843
  }
7741
7844
  }
7845
+ /**
7846
+ * Store memories from a chat transcript.
7847
+ *
7848
+ * **Experimental** until 1.0 — API shape may change.
7849
+ *
7850
+ * - `mode: "raw"` (default) — remember user message text (no LLM).
7851
+ * - `mode: "extract"` — require configured `llm`; extract atomic facts then remember each.
7852
+ */
7853
+ async rememberFromMessages(messages, options) {
7854
+ const parent = this.telemetry.start("rememberFromMessages");
7855
+ try {
7856
+ const normalized = normalizeConversationMessages(messages);
7857
+ const resolved = resolveRememberFromMessagesOptions(options);
7858
+ let texts;
7859
+ if (resolved.mode === "extract") {
7860
+ if (!this.llm) {
7861
+ throw new ProviderNotConfiguredError(
7862
+ "llm",
7863
+ "rememberFromMessages",
7864
+ 'pass llm: openaiLlm(...) in the constructor when mode is "extract"'
7865
+ );
7866
+ }
7867
+ const llmOutput = await this.llm.complete(
7868
+ buildExtractMessages(normalized)
7869
+ );
7870
+ texts = parseExtractedFacts(llmOutput);
7871
+ if (texts.length === 0) {
7872
+ parent.success({
7873
+ returnedCount: 0,
7874
+ agentId: resolved.agent,
7875
+ extra: { mode: "extract", factCount: 0 }
7876
+ });
7877
+ return [];
7878
+ }
7879
+ } else {
7880
+ texts = selectRawUserTexts(normalized, resolved.rawStrategy);
7881
+ }
7882
+ const out = [];
7883
+ for (const text of texts) {
7884
+ const child = parent.child("remember");
7885
+ const result = await this.rememberOne(
7886
+ {
7887
+ agent: resolved.agent,
7888
+ content: { text },
7889
+ ...resolved.metadata !== void 0 ? { metadata: resolved.metadata } : {},
7890
+ ...resolved.dedupe !== void 0 ? { dedupe: resolved.dedupe } : {}
7891
+ },
7892
+ child
7893
+ );
7894
+ child.success({
7895
+ provider: this.storage?.name,
7896
+ memoryIds: [result.id],
7897
+ returnedCount: 1,
7898
+ metadata: result.metadata,
7899
+ agentId: result.agent,
7900
+ tags: telemetryTags(result.metadata),
7901
+ extra: { upsertAction: result.action, mode: resolved.mode }
7902
+ });
7903
+ out.push(result);
7904
+ }
7905
+ parent.success({
7906
+ provider: this.storage?.name,
7907
+ memoryIds: out.map((r) => r.id),
7908
+ returnedCount: out.length,
7909
+ embeddingProvider: this.embedding?.model,
7910
+ model: this.embedding?.model,
7911
+ agentId: resolved.agent,
7912
+ extra: { mode: resolved.mode }
7913
+ });
7914
+ return out;
7915
+ } catch (error) {
7916
+ parent.failure(error, { agentId: options?.agent });
7917
+ throw wrapOperationError("rememberFromMessages", error);
7918
+ }
7919
+ }
7742
7920
  /**
7743
7921
  * Update an existing memory by id (re-embeds when content changes).
7744
7922
  */