@anthropic-ai/sdk
Version:
The official TypeScript library for the Anthropic API
175 lines • 8.47 kB
text/typescript
/**
* Session-level memory-store download and sync.
*
* A session may have several memory stores attached. This module resolves
* where each store's folder goes on disk, opens a {@link LocalFileStore}
* there, and reconciles each folder with its remote store — the merge rules
* live on {@link SessionMemoryStores}.
*
* Node-only (it sits on the filesystem-backed FileStore); like `skills.ts`,
* it is reachable through the shimmed `node.ts` entry point.
*/
import type { Anthropic } from "../../client.mjs";
import { AnthropicError } from "../../core/error.mjs";
import type { BetaManagedAgentsSession } from "../../resources/beta/sessions/sessions.mjs";
export { DEFAULT_MEMORY_SYNC_INTERVAL_MS, MIN_MEMORY_SYNC_INTERVAL_MS } from "./sync-interval.mjs";
/**
* Whether a locally deleted file may delete its memory on the server:
* `"enabled"` sends the delete, `"log_only"` runs the checks but only logs,
* `"disabled"` never deletes.
*/
export type MemoryDeleteMode = 'enabled' | 'log_only' | 'disabled';
/**
* Time bound the worker puts on each teardown pass — the final
* {@link SessionMemoryStores.finish}, then {@link SessionMemoryStores.flushWrites} —
* so a slow server cannot stall teardown.
*/
export declare const MEMORY_FLUSH_TIMEOUT_MS = 30000;
/**
* Marker file stamped into every store folder; a sync trusts the folder only
* when it matches. Never itself syncs.
*/
export declare const MARKER_PATH = ".anthropic-memory-store";
/** How long a file must stay missing locally before its server delete goes out. */
export declare const DELETE_CORROBORATION_MS = 30000;
/**
* How many uploads one store's flush keeps in flight. At ~0.3s per upload,
* 32 clears the server's 2000-memories-per-store cap inside
* {@link MEMORY_FLUSH_TIMEOUT_MS}.
*/
export declare const UPLOAD_CONCURRENCY = 32;
/**
* A session's memory stores could not be mounted.
*
* Thrown by {@link SessionMemoryStores.download} when a store cannot be
* materialised on disk, and by the environment worker when a work item for a
* session that has memory stores carried no sessions token to reach them with.
*/
export declare class SessionMemoryError extends AnthropicError {
constructor(message: string, cause?: unknown);
}
export interface SessionMemoryStoresOptions {
/** Base directory for the `{workdir}/memory/<name>` fallback store location. */
workdir: string;
/**
* How often (milliseconds) {@link SessionMemoryStores.syncIfDue} actually
* syncs. Defaults to {@link DEFAULT_MEMORY_SYNC_INTERVAL_MS} (15s); values
* below {@link MIN_MEMORY_SYNC_INTERVAL_MS} (5s) are rejected.
*/
syncIntervalMs?: number;
/** See {@link MemoryDeleteMode}. Defaults to `"enabled"`. */
syncDeletions?: MemoryDeleteMode;
}
/**
* The memory stores attached to one session, materialised on disk.
*
* {@link SessionMemoryStores.download} opens a {@link LocalFileStore} at each
* attached store's directory (its `mount_path`, or a workdir fallback — see
* {@link SessionMemoryStores.download}), pulls its memories, and records each
* one's `content_sha256` as the sync baseline. Each sync
* ({@link SessionMemoryStores.syncIfDue} on the worker's cadence,
* {@link SessionMemoryStores.finish} once at the end) reconciles disk against
* server, per store and per path:
*
* - a memory changed only remotely is written to disk;
* - a file changed only locally is uploaded — an update with a
* `content_sha256` precondition, or a create for a new file;
* - a file changed on both sides logs a warning and takes the server version;
* - a file the server refuses (too large, invalid content) is skipped —
* warned once and retried only after the file changes; other files keep
* syncing;
* - an upload whose response never arrives may still have been saved, so the
* sha of the bytes sent is remembered until the next sync has listed the
* server: a memory holding exactly that sha is this sync's own upload, not
* a remote edit, and a newer local edit goes out over it;
* - a file deleted locally is deleted on the server after a delay and a
* re-check — never on the first sync that notices, and only up to a
* per-sync cap. `syncDeletions` gates it;
* - a memory deleted on the server is deleted on disk — unless the local
* file holds un-pushed edits: a writable store re-creates the memory
* from the file, a read-only one keeps the file unsynced;
* - a store attached read-only pulls but never pushes.
*
* A download pulls the whole store, so it lists with content included. The
* recurring syncs instead run two phases: a content-free listing (paths and
* shas) drives the merge decisions, then only the memories actually being
* written to disk are fetched, a bounded number at a time. A sync that finds
* nothing changed moves no content at all.
*
* A file whose write to disk failed is never in the baseline, so its absence
* reads as a failed download — it is pulled again, never deleted. A write
* never re-creates a store folder that vanished mid-sync: it fails, and the
* next sync's scan finds whatever is at the path by then — nothing
* (re-downloaded) or someone else's files (left alone) — under the rules
* below.
*
* A store folder that loses its {@link MARKER_PATH} marker, is emptied,
* or vanishes is re-downloaded rather than treated as a mass local
* delete; a folder whose marker names another store is left as found —
* nothing pushed, nothing deleted.
*
* Two things about the store's directory make
* {@link SessionMemoryStores.download} refuse the session outright, with
* {@link SessionMemoryError}: a `mount_path` that is not a clean absolute
* path, and a directory already sitting at that path.
*
* {@link SessionMemoryStores.download} throws on the first store it cannot
* materialise. The syncs never throw: mid-session, one bad store or one bad
* file is logged and the rest continue. Instances are not safe for concurrent
* use. The worker builds one on its token-scoped sub-client (the memory
* endpoints reject the environment key): `syncIfDue` after each tool call,
* `finish` once at a clean end, a bounded {@link SessionMemoryStores.flushWrites}
* in every teardown, `dispose` last.
*/
export declare class SessionMemoryStores {
#private;
constructor(client: Anthropic, opts: SessionMemoryStoresOptions);
/**
* Every attached store's root directory.
*
* The worker lists these as the file tools' allowed roots so a store
* mounted outside the workdir stays reachable.
*/
get roots(): string[];
/**
* Root directories of stores attached read-only.
*
* The file tools consult this to refuse writes into read-only stores.
*/
get readOnlyRoots(): string[];
/**
* Download every attached store's memories to disk.
*
* `session` arrives already fetched — one snapshot shared with the skills
* download, so the two cannot disagree about the resources.
*/
download(session: BetaManagedAgentsSession): Promise<void>;
/**
* The session's last sync — skips the delete wait, so calling it twice
* would undo the protection; it throws instead.
*/
finish(): Promise<void>;
/** Sync when `syncIntervalMs` has elapsed since the last one. Never throws. */
syncIfDue(): Promise<void>;
/**
* Upload new and changed files; send no deletes and pull nothing.
*
* The push-only rescue pass for a session ending on an error or
* cancel — best-effort, bounded by the caller: once `signal` aborts no
* further upload starts, each store cut off part-way logs how many
* changed files it had not finished uploading, and this resolves without
* waiting for requests already in flight. Each store uploads up to
* {@link UPLOAD_CONCURRENCY} files at a time. Skips read-only stores,
* refused files, files the server already holds, and folders that fail
* the marker check. Never throws.
*/
flushWrites(signal?: AbortSignal): Promise<void>;
/**
* Remove every store directory that {@link SessionMemoryStores.download}
* created. Pre-existing directories are left alone — that is
* {@link FileStore.dispose}'s own rule. A folder that fails the marker
* check is kept too — sync left it as found, so must dispose.
*/
dispose(): Promise<void>;
}
//# sourceMappingURL=memories.d.mts.map