Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GrilloAI

GrilloAI

npm version CI npm downloads license coverage

Persistent memory for AI agents. Your agent remembers users and teams across conversations — personal preferences, shared knowledge, and context — automatically.

Install

npm install @grillo-ai/grillo-ai

Then install the packages you need:

# Pick an LLM provider (at least one required)
npm install openai             # OpenAI
npm install @anthropic-ai/sdk  # Anthropic
npm install ollama             # Ollama (local)

# Pick a storage backend (optional — InMemoryBackend is built-in)
npm install better-sqlite3     # SQLite (persistent local storage)
npm install pg                 # PostgreSQL (production)

# Pick a framework integration (optional)
npm install @openai/agents zod   # OpenAI Agents SDK
npm install @google/adk zod      # Google ADK
npm install @langchain/core zod  # LangGraph / LangChain

Quick Start

import { Grillo, InMemoryBackend, OpenAIProvider } from "@grillo-ai/grillo-ai";

const grillo = new Grillo({
  storage: new InMemoryBackend(),
  llm: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY! }),
});

// Store memories — the LLM extracts facts automatically
await grillo.addMemories(
  { userId: "alice" },
  "Hi, I'm Alice. I'm a TypeScript developer and I prefer dark mode.",
);

// Retrieve memories
const { personal } = await grillo.getMemories({ userId: "alice" });
console.log(personal?.content);
// => "- Name: Alice\n- TypeScript developer\n- Prefers dark mode"

Memories are stored as versioned markdown documents. The LLM decides what to extract, how to organize it, and automatically handles updates and contradictions.

How It Works

       Conversation
            ↓
Consciousness Router (LLM)
            ↓
┌──────────────────────┐
│ Personal memories    │  ← user preferences, individual history
│ (scoped to userId)   │
├──────────────────────┤
│ Group memories       │  ← team norms, shared knowledge
│ (scoped to groupId)  │
└──────────────────────┘
            ↓
Storage Backend (SQLite, PostgreSQL, in-memory, or custom)

When you call addMemories, GrilloAI:

  1. Loads the current personal and group memory documents
  2. Asks the LLM to update them with any new facts from the conversation
  3. Saves the updated documents as new revisions (with optimistic locking for concurrency)

Scoped Handles

For single-user contexts (chat apps, CLI tools), use .for() to bind a scope:

const memory = grillo.for({ userId: "alice", groupId: "team-1" });

await memory.addMemories("I'm working on GrilloAI.");
const { personal, group } = await memory.getMemories();

Conversation History

Pass the full conversation for better memory extraction. GrilloAI accepts result.history from the OpenAI Agents SDK (or any array of items with role and content) — no transformation needed:

// OpenAI Agents SDK — pass result.history directly
const result = await run(agent, "I just got married to Emily!");
await memory.addMemories(result.history);

You can also pass a simple array of messages or a plain string:

// Array of messages
await memory.addMemories([
  { role: "user", content: "I just got married to Emily!" },
  { role: "assistant", content: "Congratulations!" },
  { role: "user", content: "Her birthday is May 9th" },
]);

// Simple string
await memory.addMemories("My name is Alice and I prefer dark mode.");

Time Travel

Every save creates a new revision. You can read or restore any previous state:

// What did we know last week?
const { personal } = await grillo.getMemoriesAt(
  { userId: "alice" },
  new Date("2025-03-01"),
);

// Restore a single user's memories to that point
await grillo.reset({ userId: "alice" }, new Date("2025-03-01"));

// Restore both personal and group memories
await grillo.reset(
  { userId: "alice", groupId: "team-1" },
  new Date("2025-03-01"),
);

reset() restores each scope in the given object independently. If you pass both userId and groupId, both the personal and group documents are restored to the revision that existed at that timestamp.

Framework Integrations

Each integration gives you a ready-to-use tool and a recommended system prompt:

OpenAI Agents SDK

npm install @openai/agents zod
import { Grillo, OpenAIProvider } from "@grillo-ai/grillo-ai";
import { SQLiteBackend } from "@grillo-ai/grillo-ai/backends/sqlite";
import {
  createOpenAIMemoryTool,
  RECOMMENDED_PROMPT_PREFIX,
} from "@grillo-ai/grillo-ai/integrations/openai-agents";
import { Agent, run } from "@openai/agents";

const grillo = new Grillo({
  storage: new SQLiteBackend({ dbPath: "./memory.db" }),
  llm: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY! }),
});

const memoryTool = await createOpenAIMemoryTool(
  grillo.for({ userId: "alice" }),
);

const agent = new Agent({
  name: "Assistant",
  instructions: RECOMMENDED_PROMPT_PREFIX + "\n\nYou are a helpful assistant.",
  tools: [memoryTool],
});

const result = await run(agent, "Hi, I'm Alice! I prefer dark mode.");

Anthropic

npm install @anthropic-ai/sdk
import { Grillo, AnthropicProvider } from "@grillo-ai/grillo-ai";
import { SQLiteBackend } from "@grillo-ai/grillo-ai/backends/sqlite";
import {
  createAnthropicMemoryTool,
  RECOMMENDED_PROMPT_PREFIX,
} from "@grillo-ai/grillo-ai/integrations/anthropic";
import Anthropic from "@anthropic-ai/sdk";

const grillo = new Grillo({
  storage: new SQLiteBackend({ dbPath: "./memory.db" }),
  llm: new AnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY! }),
});

const memoryTool = createAnthropicMemoryTool(grillo.for({ userId: "alice" }));

const client = new Anthropic();
const response = await client.messages.create({
  model: "claude-haiku-4-5",
  max_tokens: 1024,
  system: RECOMMENDED_PROMPT_PREFIX + "\n\nYou are a helpful assistant.",
  tools: [memoryTool.definition],
  messages: [{ role: "user", content: "Hi, I'm Alice!" }],
});

// Handle tool calls
for (const block of response.content) {
  if (block.type === "tool_use" && block.name === "memory") {
    const result = await memoryTool.execute(block.input);
  }
}

Google ADK

npm install @google/adk zod
import { Grillo, OpenAIProvider } from "@grillo-ai/grillo-ai";
import { SQLiteBackend } from "@grillo-ai/grillo-ai/backends/sqlite";
import {
  createADKMemoryTool,
  RECOMMENDED_PROMPT_PREFIX,
} from "@grillo-ai/grillo-ai/integrations/google-adk";

const grillo = new Grillo({
  storage: new SQLiteBackend({ dbPath: "./memory.db" }),
  llm: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY! }),
});

const memoryTool = await createADKMemoryTool(grillo.for({ userId: "alice" }));
// Pass to your LlmAgent's tools array

LangGraph / LangChain

npm install @langchain/core zod
import { Grillo, OpenAIProvider } from "@grillo-ai/grillo-ai";
import { SQLiteBackend } from "@grillo-ai/grillo-ai/backends/sqlite";
import {
  createLangGraphMemoryTool,
  RECOMMENDED_PROMPT_PREFIX,
} from "@grillo-ai/grillo-ai/integrations/langgraph";

const grillo = new Grillo({
  storage: new SQLiteBackend({ dbPath: "./memory.db" }),
  llm: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY! }),
});

const memoryTool = await createLangGraphMemoryTool(
  grillo.for({ userId: "alice" }),
);
// Pass to your agent's tools array

LLM Providers

The LLM provider powers the consciousness router — it decides what facts to extract and how to organize the memory document.

All providers accept model to override the default, and modelOptions to pass additional SDK-specific parameters directly to the API call:

import { OpenAIProvider, AnthropicProvider, OllamaProvider } from "@grillo-ai/grillo-ai";

// OpenAI (default model: gpt-5-mini)
const llm = new OpenAIProvider({
  apiKey: process.env.OPENAI_API_KEY!,
});

// OpenAI with reasoning
const llm = new OpenAIProvider({
  apiKey: process.env.OPENAI_API_KEY!,
  model: "gpt-5.4",
  modelOptions: { reasoning: { effort: "low" } },
});

// Anthropic (default model: claude-haiku-4-5)
const llm = new AnthropicProvider({
  apiKey: process.env.ANTHROPIC_API_KEY!,
});

// Anthropic with extended thinking
const llm = new AnthropicProvider({
  apiKey: process.env.ANTHROPIC_API_KEY!,
  model: "claude-sonnet-4-5",
  modelOptions: { thinking: { type: "enabled", budget_tokens: 5000 } },
});

// Ollama — fully local, no API key (model is required)
const llm = new OllamaProvider({ model: "qwen3.5" });

modelOptions is spread directly into the API call, so any parameter supported by the SDK works.

Storage Backends

GrilloAI ships with three backends. You can also build your own by implementing the StorageBackend interface (getDocument, saveDocument, getDocumentAt).

// In-memory — built-in, no extra install. Good for dev/test.
import { InMemoryBackend } from "@grillo-ai/grillo-ai";
const storage = new InMemoryBackend();

// SQLite — persistent local storage.
// npm install better-sqlite3
import { SQLiteBackend } from "@grillo-ai/grillo-ai/backends/sqlite";
const storage = new SQLiteBackend({ dbPath: "./memory.db" });

// PostgreSQL — production deployments.
// npm install pg
import { PostgresBackend } from "@grillo-ai/grillo-ai/backends/postgres";
const storage = new PostgresBackend({
  connectionString: process.env.DATABASE_URL!,
});

Custom Backends

Implement the StorageBackend interface to use any database:

import type { StorageBackend } from "@grillo-ai/grillo-ai";

class MyCustomBackend implements StorageBackend {
  async getDocument(scope) {
    /* return latest revision or null */
  }
  async saveDocument(scope, content, expectedVersion?) {
    /* save new revision */
  }
  async getDocumentAt(scope, timestamp) {
    /* return revision at timestamp or null */
  }
}

Group Memory Approval

When your scope includes a groupId, the consciousness router may decide to update shared group memories. You can intercept this with an approval callback to let the user decide:

// Express.js example — show the user a confirmation dialog
const grillo = new Grillo({
  storage,
  llm,
  onGroupMemoryUpdate: async (proposedContent) => {
    // `proposedContent` is the full updated group memory document.
    // Return true to save it, false to discard.
    // How you ask for approval depends on your app:

    // CLI app:
    console.log("Proposed group memory:\n" + proposedContent);
    return await askYesNo("Save to group memory?");

    // Web app (via WebSocket, SSE, etc.):
    return await sendApprovalRequest(userId, proposedContent);

    // Auto-approve (default behavior when callback is not set):
    return true;
  },
});

When onGroupMemoryUpdate is set:

  • Personal memories are always saved immediately — no approval needed
  • Group memories are passed to your callback first — only saved if you return true

When onGroupMemoryUpdate is not set, group memories are saved automatically (no approval step).

API

const grillo = new Grillo({ storage, llm, onGroupMemoryUpdate? });
Parameter Type Description
storage StorageBackend Where to store memory documents (InMemoryBackend, SQLiteBackend, PostgresBackend, or custom)
llm LLMProvider LLM for the consciousness router (OpenAIProvider, AnthropicProvider, OllamaProvider)
onGroupMemoryUpdate (content: string) => Promise<boolean> Optional. Called before saving group memories. Return true to save, false to discard.

Methods

// With explicit scope
grillo.getMemories(scope); // → { personal: MemoryDocument | null, group: MemoryDocument | null }
grillo.addMemories(scope, input); // input: string or { role, content }[]
grillo.getMemoriesAt(scope, timestamp); // → memories at that point in time
grillo.reset(scope, timestamp); // restore to a previous revision

// With a scoped handle
const memory = grillo.for(scope);
memory.getMemories();
memory.addMemories(input);
memory.getMemoriesAt(timestamp);
memory.reset(timestamp);

Types

// Scope — identifies whose memory this is
{ orgId?: string, userId?: string, groupId?: string }

// MemoryDocument — a versioned memory document
{ content: string, version: number, updatedAt: Date }

// Memories — returned by getMemories()
{ personal: MemoryDocument | null, group: MemoryDocument | null }

Examples

See the examples/ directory for working chat applications.

Contributing

See CONTRIBUTING.md for development setup and release process.

License

MIT

About

Persistent memory for AI agents. Your agent remembers users and teams across conversations — personal preferences, shared knowledge, and context — automatically.

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages