Guides

TypeScript quickstart

Install the TypeScript SDK and give your app working memory in under 10 minutes — copy, paste, run.

This is the fastest path from nothing to a running Aether integration in TypeScript or JavaScript. You'll install the SDK, set one environment variable, and store and recall per-user memories. Every snippet below is complete and runnable.

1. Install the SDK

Bash
npm install @aether-ai/sdk

The SDK ships full type definitions and uses the native fetch API, so it runs on Node.js 18+ and modern runtimes with no extra dependencies. pnpm add and yarn add work too.

Use ESM imports in modern TypeScript and JavaScript projects:

TypeScript
import { AetherClient } from "@aether-ai/sdk";

CommonJS works too:

JavaScript
const { AetherClient } = require("@aether-ai/sdk");

2. Set your API key

Create a key in the Aether Dashboard and make it available as an environment variable. Keep it out of your source — load it from the environment, a .env file, or your secrets manager.

Bash
export AETHER_API_KEY="your-api-key"

3. Store and recall memory

The Memory facade is the shortcut for per-user or per-agent memory. You give it an entityId (a user, agent, session — whatever you want to scope memory to), then remember and recall in plain language. Every operation is automatically scoped to that entity, so one user never sees another's memories.

TypeScript
import { Memory } from "@aether-ai/sdk";

// Scope all memory to one entity (here, a user)
const memory = new Memory("user-42", { apiKey: process.env.AETHER_API_KEY });

// Store a few memories
await memory.remember("Prefers concise, bullet-point answers");
await memory.remember("Working on a Next.js + Postgres side project");
await memory.remember("Based in Berlin; books meetings in CET");

// Recall the most relevant ones for a query
const hits = await memory.recall("how should I format my replies?", { k: 3 });
for (const item of hits) {
  console.log(item.score?.toFixed(3), item.text);
}

Run it. recall returns the memories ranked by relevance — the formatting preference comes back first, because Aether searches by meaning, not keywords:

text
0.610 Prefers concise, bullet-point answers
0.420 Working on a Next.js + Postgres side project
0.310 Based in Berlin; books meetings in CET

Each item carries the remembered text, its underlying id, and a score (higher is more relevant; the value is relative within a single recall call). That's working memory — persistent across requests, scoped to the entity, no schema to manage.

Use it in a prompt

To ground an LLM reply, recall the relevant memories and fold them into your system prompt:

TypeScript
const memories = await memory.recall(userMessage, { k: 5 });
const context = memories.map((m) => `- ${m.text}`).join("\n");
const system = `What you know about this user:\n${context}`;

4. Manage memories

The same facade lists and deletes memories, all scoped to the entity:

TypeScript
// Newest-first chronological view
for (const item of await memory.list({ limit: 10 })) {
  console.log(item.id, item.text);
}

// Delete one memory, or wipe everything for this entity
await memory.forget("doc-id-from-a-memory-item");
const deleted = await memory.forgetAll();
console.log(`Deleted ${deleted} memories`);

5. Document round-trip

When you need direct control over documents and search instead of per-entity memory, use AetherClient. This is the lowest-friction round trip: insert text, search by meaning, and print the matched passage.

TypeScript
import { AetherClient } from "@aether-ai/sdk";

const client = new AetherClient({ apiKey: process.env.AETHER_API_KEY });

const doc = await client.insertText(
  "Employees accrue 20 days of PTO per year.",
  { filename: "pto-policy.txt" }
);
console.log("inserted", doc.doc_id);

const results = await client.search("vacation days", 3);
for (const hit of results) {
  console.log(hit.score, hit.doc_id, hit.passage);
}

Use retrieve instead of search when you want full document text for a RAG prompt:

TypeScript
const results = await client.retrieve("How much PTO do employees get?", 3);
for (const hit of results) {
  console.log(hit.score, hit.content);
}

Use search instead of retrieve when you only need the ranked passage and score without downloading full content. See the 5-minute RAG guide for the full retrieve-then-generate pattern.

6. Handle errors

Catch AetherApiError for HTTP responses from Aether. Inspect status, errorCode, and the concrete subclass to decide whether to retry, show an upgrade prompt, or fail fast.

TypeScript
import {
  AetherApiError,
  AetherClient,
  FreeLimitExceededError,
} from "@aether-ai/sdk";

const client = new AetherClient();

try {
  await client.insertText("Important note", { filename: "note.txt" });
} catch (error) {
  if (error instanceof FreeLimitExceededError) {
    console.log("Plan limit reached. Upgrade before retrying this insert.");
  } else if (error instanceof AetherApiError && error.status === 429) {
    console.log("Rate limited. Back off before retrying.");
  } else if (error instanceof AetherApiError && [502, 503, 504].includes(error.status)) {
    console.log(`Transient Aether error: ${error.status}`);
  } else {
    throw error;
  }
}

Next steps