@memstack/core 0.2.0 → 0.4.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/README.md CHANGED
@@ -83,11 +83,12 @@ Think of it as the open-source alternative to [Mem0](https://mem0.ai/) — plugg
83
83
  ## Quick Start
84
84
 
85
85
  ```typescript
86
- import { MemStack, OpenAILLMAdapter, OpenAIEmbeddingAdapter } from "@memstack/core";
86
+ import { MemStack, OpenAILLMAdapter, OpenAIEmbeddingAdapter, InMemoryStorageAdapter } from "@memstack/core";
87
87
 
88
88
  const memstack = new MemStack({
89
89
  llm: new OpenAILLMAdapter({ apiKey: process.env.OPENAI_API_KEY! }),
90
90
  embedding: new OpenAIEmbeddingAdapter({ apiKey: process.env.OPENAI_API_KEY! }),
91
+ storage: new InMemoryStorageAdapter(),
91
92
  });
92
93
 
93
94
  // 1. Store what happened
@@ -134,7 +135,7 @@ Every agent interaction becomes a `Memory` with metadata that controls how it's
134
135
  interface Memory {
135
136
  id: string;
136
137
  actorId: string; // Who this memory belongs to (user ID, agent ID, session ID)
137
- memoryType: MemoryType; // "interaction" | "summary" | "observation"
138
+ memoryType: MemoryType; // "interaction" | "summary" | "observation" | "fact" | "reflection"
138
139
  content: string; // The actual text
139
140
  importance: number; // 0-1 — higher = survives pruning, ranks higher in retrieval
140
141
  emotionalValence: number; // -1 to 1 — for tone-aware retrieval
@@ -403,7 +404,8 @@ const userCount = await ms.memory.count({ actorId: "user-42" });
403
404
  | `interaction` | Default. Direct exchanges between agent and user/other agent. | "User asked about billing." |
404
405
  | `summary` | Compressed collection of old interactions. Created by `summarize()`. | "Over 3 weeks, user reported 5 login failures..." |
405
406
  | `observation` | Passive knowledge — facts, documents, things the agent knows but didn't interact with. | "Company refund policy is 30 days from purchase." |
406
- | `gossip` | Information about third parties. For multi-agent systems. | "Agent-B told me the user is a power user." |
407
+ | `fact` | Verified knowledge — discrete truths the agent has confirmed. | "The user's subscription tier is Enterprise." |
408
+ | `reflection` | Self-generated insight — the agent thinking about its own experiences. | "I tend to over-explain billing policies — should be more concise." |
407
409
 
408
410
  Types control retrieval behavior — `compileContext()` treats `interaction` and `summary` differently from `observation`. Use types to separate "what happened" from "what I know."
409
411
 
@@ -462,16 +464,17 @@ MemStack is provider-agnostic. Every boundary is an interface — bring your own
462
464
 
463
465
  ### LLM Adapters
464
466
 
465
- Used by `summarize()` and `compileContext()`. Ships with OpenAI and Anthropic built-in.
467
+ Used by `summarize()` and `compileContext()`. Ships with OpenAI, Anthropic, Ollama, and Groq built-in — and via `baseURL`, the OpenAI adapter works with **any OpenAI-compatible API** (DeepSeek, Mistral, Gemini, Together AI, Perplexity, Fireworks, xAI, and dozens more).
466
468
 
467
469
  ```typescript
468
470
  // OpenAI
469
471
  import { OpenAILLMAdapter } from "@memstack/core";
470
- const llm = new OpenAILLMAdapter({
471
- apiKey: process.env.OPENAI_API_KEY!,
472
- defaultModel: "gpt-4o-mini", // default
473
- baseURL: "https://api.openai.com/v1", // for proxies like LiteLLM
474
- });
472
+ const llm = new OpenAILLMAdapter({ apiKey: "..." });
473
+
474
+ // Any OpenAI-compatible API — just change baseURL
475
+ const deepseek = new OpenAILLMAdapter({ apiKey: "...", baseURL: "https://api.deepseek.com/v1" });
476
+ const mistral = new OpenAILLMAdapter({ apiKey: "...", baseURL: "https://api.mistral.ai/v1" });
477
+ const together = new OpenAILLMAdapter({ apiKey: "...", baseURL: "https://api.together.xyz/v1" });
475
478
 
476
479
  // Anthropic
477
480
  import { AnthropicLLMAdapter } from "@memstack/core";
@@ -480,62 +483,147 @@ const llm = new AnthropicLLMAdapter({
480
483
  defaultModel: "claude-sonnet-4-5-20250929",
481
484
  });
482
485
 
483
- // Ollama (custom — implement LLMProvider)
484
- import type { LLMProvider } from "@memstack/core";
485
- class OllamaAdapter implements LLMProvider {
486
- constructor(private baseURL = "http://localhost:11434") {}
487
- async complete(req: { system: string; user: string; model?: string }) {
488
- const res = await fetch(`${this.baseURL}/api/generate`, {
489
- method: "POST",
490
- body: JSON.stringify({ model: req.model ?? "llama3.2", prompt: `${req.system}\n\n${req.user}`, stream: false }),
491
- });
492
- const data = await res.json() as { response: string };
493
- return { text: data.response, tokens: { prompt: 0, completion: 0, total: 0 } };
494
- }
495
- }
486
+ // Ollama (built-in)
487
+ import { OllamaLLMAdapter } from "@memstack/core";
488
+ const llm = new OllamaLLMAdapter({
489
+ baseURL: "http://localhost:11434",
490
+ defaultModel: "llama3.2",
491
+ });
496
492
  ```
497
493
 
498
494
  ### Embedding Adapters
499
495
 
500
- Used by semantic retrieval. Ships with OpenAI built-in.
496
+ Used by semantic retrieval. Ships with OpenAI and Cohere built-in — and via `baseURL`, the OpenAI adapter works with **any OpenAI-compatible embedding API** (Together AI, Voyage AI, Jina, Nomic, and more).
501
497
 
502
498
  ```typescript
503
- import { OpenAIEmbeddingAdapter } from "@memstack/core";
504
- const embedding = new OpenAIEmbeddingAdapter({
505
- apiKey: process.env.OPENAI_API_KEY!,
506
- model: "text-embedding-3-small", // 1536 dimensions (default)
507
- // model: "text-embedding-3-large", // 3072 dimensions
508
- });
509
- ```
499
+ import { OpenAIEmbeddingAdapter, CohereEmbeddingAdapter } from "@memstack/core";
510
500
 
511
- ### Storage Adapters
501
+ // OpenAI
502
+ new OpenAIEmbeddingAdapter({ apiKey: "...", model: "text-embedding-3-small" }); // 1536 dims
512
503
 
513
- Ships with `InMemoryStorage` (zero setup, data lost on restart). For production, implement `StorageProvider` for your database.
504
+ // Cohere
505
+ new CohereEmbeddingAdapter({ apiKey: "..." }); // embed-english-v3.0, 1024 dims
514
506
 
515
- ```typescript
516
- import { InMemoryStorage } from "@memstack/core";
517
- const storage = new InMemoryStorage();
507
+ // Any OpenAI-compatible embedding API
508
+ new OpenAIEmbeddingAdapter({ apiKey: "...", baseURL: "https://api.voyageai.com/v1", model: "voyage-3" });
518
509
  ```
519
510
 
520
- **Custom storage** — implement `StorageProvider`:
511
+ ### Storage Adapters
521
512
 
522
- ```typescript
513
+ MemStack ships with **11 production-ready storage adapters (7 experimental)** — every major backend, zero peer dependencies, all client-injected.
514
+
515
+ **Built-in (zero external deps):**
516
+ | Adapter | Backend | Use case |
517
+ |---|---|---|
518
+ | `InMemoryStorageAdapter` | In-memory Map | Testing, prototyping |
519
+ | `DiskStorageAdapter` | Local JSON files | Simple local persistence |
520
+ | `MarkdownStorageAdapter` | Append-only .md files | Human-readable, git-diffable, debug-friendly |
521
+ | `HybridStorageAdapter` | Compose any two StorageProviders | Cache + durable, edge + durable |
522
+
523
+ **Relational / SQL:**
524
+ | Adapter | Backend | Vector search |
525
+ |---|---|---|
526
+ | `PostgresStorageAdapter` | PostgreSQL + pgvector | HNSW native |
527
+ | `SQLiteStorageAdapter` | SQLite (better-sqlite3) | In-memory cosine |
528
+ | `TursoStorageAdapter` | Turso (libsql) | DiskANN native |
529
+
530
+ **Aggregators:**
531
+ | Adapter | Delegates to |
532
+ |---|---|
533
+ | `Mem0StorageAdapter` | Mem0 OSS or Cloud |
534
+ | `ZepStorageAdapter` | Zep Cloud or Community Edition |
535
+
536
+ **Vector databases:**
537
+ | Adapter | Backend |
538
+ |---|---|
539
+ | `QdrantStorageAdapter` | Qdrant |
540
+ | `PineconeStorageAdapter` | Pinecone |
541
+ | `ChromaStorageAdapter` | ChromaDB |
542
+ | `WeaviateStorageAdapter` | Weaviate |
543
+ | `LanceDBStorageAdapter` | LanceDB |
544
+ | `MongoDBStorageAdapter` | MongoDB Atlas Vector Search |
545
+
546
+ **Cache / KV:**
547
+ | Adapter | Backend |
548
+ |---|---|
549
+ | `RedisStorageAdapter` | Redis (ioredis) |
550
+ | `UpstashStorageAdapter` | Upstash Redis + Vector |
551
+
552
+ **Graph:**
553
+ | Adapter | Backend |
554
+ |---|---|
555
+ | `Neo4jStorageAdapter` | Neo4j |
556
+
557
+ **Quick-start per backend:**
558
+
559
+ ```ts
560
+ // Postgres
561
+ import { PostgresStorageAdapter } from "@memstack/core";
562
+ const storage = new PostgresStorageAdapter({ connectionString: "postgres://..." });
563
+
564
+ // SQLite
565
+ import Database from "better-sqlite3";
566
+ import { SQLiteStorageAdapter } from "@memstack/core";
567
+ const storage = new SQLiteStorageAdapter({ db: new Database("memory.db") });
568
+
569
+ // Redis
570
+ import Redis from "ioredis";
571
+ import { RedisStorageAdapter } from "@memstack/core";
572
+ const storage = new RedisStorageAdapter({ redis: new Redis() });
573
+
574
+ // Markdown (append-only, human-readable)
575
+ import { MarkdownStorageAdapter } from "@memstack/core";
576
+ const storage = new MarkdownStorageAdapter({ dir: "./memories" });
577
+
578
+ // Hybrid (Redis cache + Postgres durable)
579
+ import { HybridStorageAdapter } from "@memstack/core";
580
+ const storage = new HybridStorageAdapter({
581
+ cache: new RedisStorageAdapter({ redis: new Redis() }),
582
+ durable: new PostgresStorageAdapter({ connectionString: "postgres://..." }),
583
+ });
584
+ ```
585
+
586
+ **Custom storage:**
587
+ ```ts
523
588
  import type { StorageProvider, MemoryStoreInput } from "@memstack/core";
524
589
 
525
- class PostgresStorage implements StorageProvider {
526
- async store(input: MemoryStoreInput): Promise<Memory> { /* INSERT */ }
527
- async get(id: string): Promise<Memory | null> { /* SELECT */ }
528
- async retrieve(query: MemoryRetrieveQuery, embedding?: number[]): Promise<Memory[]> { /* SELECT + filters */ }
529
- async count(filter?: MemoryCountFilter): Promise<number> { /* SELECT COUNT */ }
530
- async delete(id: string): Promise<void> { /* DELETE */ }
531
- async deleteMany(ids: string[]): Promise<number> { /* DELETE batch */ }
532
- async storeBatch(inputs: MemoryStoreInput[]): Promise<Memory[]> { /* INSERT batch */ }
533
- async initialize(): Promise<void> { /* CREATE TABLE */ }
534
- async close(): Promise<void> { /* close pool */ }
590
+ class MyStorage implements StorageProvider {
591
+ async store(input: MemoryStoreInput): Promise<Memory> { /* ... */ }
592
+ async get(id: string): Promise<Memory | null> { /* ... */ }
593
+ async retrieve(query: MemoryRetrieveQuery, embedding?: number[]): Promise<Memory[]> { /* ... */ }
594
+ async count(filter?: MemoryCountFilter): Promise<number> { /* ... */ }
595
+ async delete(id: string): Promise<void> { /* ... */ }
596
+ async deleteMany(ids: string[]): Promise<number> { /* ... */ }
597
+ async storeBatch(inputs: MemoryStoreInput[]): Promise<Memory[]> { /* ... */ }
598
+ async initialize(): Promise<void> { /* ... */ }
599
+ async close(): Promise<void> { /* ... */ }
535
600
  }
536
601
  ```
537
602
 
538
- See `src/adapters/storage/memory.ts` for a complete reference implementation.
603
+ ---
604
+
605
+ ## Backend Comparison
606
+
607
+ | Backend | Vector search | Touch | Best for |
608
+ |---|---|---|---|
609
+ | InMemory | Cosine in-memory | Yes | Testing, prototyping |
610
+ | Disk (JSON) | Keyword + importance | Yes | Simple local persistence |
611
+ | Markdown | Keyword + importance | No | Human-readable, git-diffable |
612
+ | Postgres | pgvector HNSW | Yes | Production relational |
613
+ | SQLite | Cosine in-memory | Yes | Local dev, solo apps |
614
+ | Turso | DiskANN native | Yes | Edge/serverless |
615
+ | Redis | RediSearch KNN (auto-detect) | Yes | Sub-5ms hot session state |
616
+ | Upstash | Native vector (vector mode) | No | CF Workers, Vercel Edge |
617
+ | Qdrant | ANN native | No | Best filtered search |
618
+ | Pinecone | ANN native | No | Zero-ops managed |
619
+ | Chroma | Native | No | LangChain prototyping |
620
+ | Weaviate | BM25 + vector hybrid | No | Hybrid search |
621
+ | LanceDB | DiskANN native | No | Embedded local vector |
622
+ | MongoDB | Atlas Vector Search | No | Existing MongoDB deployments |
623
+ | Neo4j | Neo4j vector index | No | Relationship-aware agents |
624
+ | Hybrid | Delegates to cache/durable | If durable supports | Read-through cache pattern |
625
+ | Mem0 | Delegates to Mem0 | No | Multi-backend via Mem0 |
626
+ | Zep | Graphiti temporal graph | No | Temporal graph memory |
539
627
 
540
628
  ---
541
629
 
@@ -549,7 +637,7 @@ import { MemStack } from "@memstack/core";
549
637
  const ms = new MemStack({
550
638
  llm: LLMProvider, // Required — for summarization
551
639
  embedding?: EmbeddingProvider, // Optional — for semantic search
552
- storage?: StorageProvider, // Optional — defaults to InMemoryStorage
640
+ storage?: StorageProvider, // Optional — defaults to InMemoryStorageAdapter
553
641
  defaults?: {
554
642
  summarizationThreshold?: number, // Auto-summarize every N interactions. Default: 100
555
643
  embedOnStore?: boolean, // Auto-embed on store(). Default: true
@@ -696,7 +784,7 @@ git clone https://github.com/isiomaC/memstack.git
696
784
  cd memstack
697
785
  pnpm install
698
786
 
699
- pnpm test # 56 tests, no external services needed
787
+ pnpm test # 393 tests, no external services needed
700
788
  pnpm test:watch # Watch mode
701
789
  pnpm build # CJS + ESM + type declarations
702
790
  pnpm check # TypeScript type-check only
@@ -723,7 +811,7 @@ const ms = new MemStack({
723
811
  | `CONFIG_ERROR: LLM provider is required` | No LLM adapter | Pass any `LLMProvider` to config |
724
812
  | Empty retrieval results | Wrong `actorId` or no memories stored | Check `await ms.memory.count({ actorId })` |
725
813
  | Semantic search not working | No embedding adapter or `embedOnStore: false` | Add embedding adapter or use `strategy: "recent"` |
726
- | High memory usage in production | Using InMemoryStorage | Implement `StorageProvider` for Postgres/Redis/etc |
814
+ | High memory usage in production | Using InMemoryStorageAdapter | Implement `StorageProvider` for Postgres/Redis/etc |
727
815
  | Poor summarization quality | Default prompt doesn't match your domain | Use `summarizationPrompt` in `defaults` config |
728
816
 
729
817
  **Inspecting state at runtime:**
@@ -759,11 +847,11 @@ The `@memstack` scope requires `--access public` on first publish.
759
847
 
760
848
  Most needed contributions:
761
849
 
762
- - **Storage adapters**: Postgres, Redis, SQLite, filesystem
763
- - **LLM adapters**: Ollama, Groq, Together AI, Gemini
764
- - **Embedding adapters**: Cohere, Voyage AI, local transformers.js
765
- - **Tests**: Edge cases, concurrent access, large-scale benchmarks
766
- - **Docs**: Architecture diagrams, tutorials
850
+ - **Docker Compose** for integration testing
851
+ - **LLM adapters**: Google Gemini (native), Amazon Bedrock, Vertex AI
852
+ - **Embedding adapters**: local inference (transformers.js, ONNX)
853
+ - **Benchmarks**: retrieval quality, latency, cost comparisons
854
+ - **Python port**: `pip install memstack`
767
855
 
768
856
  Open an issue or PR at [github.com/isiomaC/memstack](https://github.com/isiomaC/memstack).
769
857