The TypeScript SDK is an HTTP client that connects to the REST API server. It handles timeout, retry with exponential backoff, and structured errors.

Install

bun add pensyve

Or with npm:

npm install pensyve

Initialize

import { Pensyve } from "pensyve";

const p = new Pensyve({
  baseUrl: "http://localhost:8000",
  timeoutMs: 10_000,  // default: 30000
  retries: 2,         // default: 2, retries on 5xx
});

The REST API server must be running. See Installation.

Create an Entity

const user = await p.entity("alice", "user");
console.log(user);
// { id: "550e8400-...", name: "alice", kind: "user" }

Remember

const mem = await p.remember({
  entity: "alice",
  fact: "Alice prefers TypeScript over JavaScript",
  confidence: 0.9,
});

console.log(mem.memoryType);  // "semantic"
console.log(mem.confidence);  // 0.9

Recall

const memories = await p.recall("programming language preference", {
  entity: "alice",
  limit: 5,
});

for (const m of memories) {
  console.log(`[${m.memoryType}] ${m.content} (score=${m.score})`);
}

Filtering by Type

const semantic = await p.recall("preferences", {
  entity: "alice",
  types: ["semantic"],
});

Episodes

Episodes use a handle-based API since there is no with statement equivalent.

const ep = await p.startEpisode(["alice", "assistant"]);

await ep.addMessage("user", "I prefer dark mode");
await ep.addMessage("assistant", "Got it!");
ep.setOutcome("success");

const result = await ep.end();
console.log(result.memoriesCreated);  // number of memories extracted

Consolidation

const stats = await p.consolidate();
console.log(stats);
// { promoted: 2, decayed: 5, archived: 1 }

Error Handling

The SDK throws PensyveError for HTTP errors with structured details:

import { Pensyve, PensyveError } from "pensyve";

try {
  await p.recall("query", { entity: "nonexistent" });
} catch (err) {
  if (err instanceof PensyveError) {
    console.error(err.status);      // 404
    console.error(err.statusText);  // "Not Found"
    console.error(err.detail);      // server error detail
    console.error(err.endpoint);    // "Recall"
  }
}

4xx errors are not retried. 5xx errors and network failures are retried up to retries times with exponential backoff.

Types

The SDK exports these types:

interface PensyveConfig {
  baseUrl: string;
  namespace?: string;
  timeoutMs?: number;       // default: 30000
  retries?: number;         // default: 2
  retryBaseDelayMs?: number; // default: 500
  fetch?: typeof fetch;     // custom fetch impl
}

interface Entity {
  id: string;
  name: string;
  kind: string;
}

interface Memory {
  id: string;
  content: string;
  memoryType: "episodic" | "semantic" | "procedural";
  confidence: number;
  stability: number;
  score?: number;
}

interface RecallOptions {
  entity?: string;
  limit?: number;
  types?: Array<"episodic" | "semantic" | "procedural">;
}

interface RememberOptions {
  entity: string;
  fact: string;
  confidence?: number;
}

interface EpisodeHandle {
  addMessage(role: string, content: string): Promise<void>;
  setOutcome(outcome: "success" | "failure" | "partial"): void;
  end(): Promise<{ memoriesCreated: number }>;
}

Full Example

import { Pensyve } from "pensyve";

const p = new Pensyve({ baseUrl: "http://localhost:8000" });

// Create entities
await p.entity("assistant", "agent");
await p.entity("alice", "user");

// Record an episode
const ep = await p.startEpisode(["alice", "assistant"]);
await ep.addMessage("user", "I always use dark mode");
await ep.addMessage("assistant", "Noted!");
ep.setOutcome("success");
await ep.end();

// Store a fact
await p.remember({
  entity: "alice",
  fact: "Alice is a backend engineer",
  confidence: 0.9,
});

// Recall
const memories = await p.recall("what does alice do?", { entity: "alice" });
for (const m of memories) {
  console.log(`[${m.memoryType}] ${m.content}`);
}