Skip to content

TypeScript SDK

The TypeScript SDK (@memoturn/sdk on npm) provides tracing, prompt management, and an OpenAI wrapper. Configure it via the constructor or the env vars MEMOTURN_BASE_URL, MEMOTURN_PUBLIC_KEY, MEMOTURN_SECRET_KEY, MEMOTURN_ENVIRONMENT, MEMOTURN_MAX_BUFFER_SIZE (buffered-event cap, default 10000), and MEMOTURN_ALLOW_HTTP (suppress the cleartext-http warning for non-local hosts).

Flushing is request-sized: a large buffer (e.g. after an outage) is sent as several POST /v1/ingest calls of at most 1000 events / ~10 MB each (maxBatchSize), never one over-limit request the API would reject. After a transient failure the background flusher backs off exponentially with jitter (honouring Retry-After); an explicit flush() always tries. Set flushOnSignals: true to also flush on SIGTERM/SIGINT in containers.

import { Memoturn } from "@memoturn/sdk";
const mt = new Memoturn({
baseUrl: "http://localhost:3001",
publicKey: "pk-mt-dev",
secretKey: "sk-mt-dev",
});
const trace = mt.trace({ name: "rag", userId: "u1", sessionId: "s1", sessionPath: "/rag", input: { q } });
const retrieval = trace.span({ name: "retrieve", input: { q } });
retrieval.end({ output: docs });
const gen = trace.generation({
name: "answer",
model: "claude-sonnet-4-6",
modelParameters: { temperature: 0.2 },
input: messages,
});
gen.end({ output: reply, usage: { promptTokens: 320, completionTokens: 24 } });
trace.update({ output: reply });
trace.score({ name: "user-feedback", value: 1, comment: "helpful" });
await mt.shutdown(); // flush before exit

The client batches events and flushes on size, on an interval, and at shutdown. Spans and generations can nest via span.span({...}).

import OpenAI from "openai";
import { wrapOpenAI } from "@memoturn/sdk";
const openai = wrapOpenAI(new OpenAI(), mt);
await openai.chat.completions.create({ model: "gpt-4o-mini", messages }); // recorded
import { MemoturnCallback } from "@memoturn/sdk";
const handler = new MemoturnCallback(mt);
await chain.invoke(input, { callbacks: [handler] });
await handler.flush();
import { getPrompt, compilePrompt } from "@memoturn/sdk";
const prompt = await getPrompt(
{ baseUrl, publicKey, secretKey },
"support-reply",
{ channel: "production" },
);
const messages = compilePrompt(prompt, { product: "memoturn", question: q });

getPrompt caches in memory (default TTL 60s) and serves stale-while-revalidate, so a resolve on your request path costs nothing most of the time and never blocks on a slow control plane. If the fetch fails it keeps serving the cached value; with nothing cached it returns fallback when you supply one, otherwise it throws.

const prompt = await getPrompt(creds, "support-reply", {
cacheTtlMs: 300_000,
fallback: { name: "support-reply", version: 0, type: "TEXT", content: "", config: {} },
});

Set cacheTtlMs: 0 to disable caching, or call clearPromptCache() to force a refetch.

import { createDataset, addDatasetItems, getDataset } from "@memoturn/sdk";
await createDataset(creds, "qa-eval");
await addDatasetItems(creds, "qa-eval", [{ input: { q }, expectedOutput: "" }]);
const ds = await getDataset(creds, "qa-eval");
const links = [];
for (const item of ds.items) {
const trace = mt.trace({ name: "qa-run", input: item.input });
// …run your task, end generations…
links.push({ datasetItemId: item.id, traceId: trace.id });
}
await mt.shutdown();
await ds.recordRun("baseline-v1", links);