@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
88 lines (87 loc) • 3.93 kB
TypeScript
/**
* Artifact Store
*
* Pluggable storage for externalized MCP tool outputs.
*
* When `mcp.outputLimits.strategy = "externalize"` the full tool payload is
* written here instead of being sent inline to the LLM. The model receives a
* compact surrogate with a preview and an artifact ID. The full payload can be
* retrieved on demand via the `retrieve_context` tool.
*
* Architecture:
* ArtifactStore (interface) — canonical types in src/lib/types/artifactTypes.ts
* LocalTempArtifactStore — single-process, filesystem-backed implementation
*
* `RedisArtifactStore` is the shared-across-replicas backend; anything else
* (S3, a database) implements ArtifactStore and is injected via
* `artifacts.store` or `setArtifactStore()`.
*
* @module artifacts/artifactStore
*/
import type { ArtifactMeta, ArtifactRef, ArtifactStore } from "../types/index.js";
/**
* Filesystem-backed artifact store using the OS temp directory.
*
* Files are written with mode 0o600 (owner read/write only).
* An in-memory index tracks metadata for the fast path; every payload also
* gets a `<id>.meta.json` sidecar, so an id this process never stored — from
* another process, or from before a restart — still resolves (see
* `rehydrate`). `cleanup()` remains index-scoped: it expires what this process
* knows about, and never walks the directory deleting another process's work.
*
* @example
* ```typescript
* const store = new LocalTempArtifactStore();
* const ref = await store.store(largeJson, {
* toolName: "list_files",
* serverId: "filesystem-server",
* sizeBytes: Buffer.byteLength(largeJson),
* contentType: "json",
* });
* // Later, via retrieve_context:
* const full = await store.retrieve(ref.id);
* ```
*/
export declare class LocalTempArtifactStore implements ArtifactStore {
private readonly dir;
private readonly index;
private readonly rehydrateFromDisk;
/**
* @param dir - Storage directory; defaults to `tmpdir()/neurolink-artifacts`
* @param options - `rehydrateFromDisk` (default true) lets `retrieve()` and
* `delete()` fall back to the on-disk sidecar index on an in-memory miss,
* which makes artifacts READABLE AND DELETABLE ACROSS PROCESSES sharing
* the same directory and unix user. Pass `false` — or set
* `NEUROLINK_ARTIFACT_REHYDRATE=false` — to restore strict per-process
* isolation: ids not stored by this process resolve to nothing.
*/
constructor(dir?: string, options?: {
rehydrateFromDisk?: boolean;
});
generatePreview(payload: string): string;
store(payload: string, meta: Omit<ArtifactMeta, "createdAt">): Promise<ArtifactRef>;
retrieve(id: string): Promise<string | null>;
delete(id: string): Promise<void>;
cleanup(olderThanMs: number): Promise<number>;
/**
* Record the index row next to the payload.
*
* The index is per-process, so without this an artifact written by one
* process is invisible to every other one — and to the same process after a
* restart. A failed sidecar write is logged, never fatal: the payload is
* already safely on disk and this process can still read it from its index.
*/
private writeSidecar;
/**
* Resolve an id the in-memory index does not know: another process stored
* it, or this process restarted. Reads the sidecar first (full metadata);
* falls back to probing the payload file itself, so an artifact whose
* sidecar was lost is still readable with metadata recovered from `stat`.
*
* Returns undefined for an unsafe id without touching the filesystem: before
* this fallback existed an unknown id simply missed the in-memory map, and
* now that a miss probes `join(dir, id + ext)` the id — which arrives from
* the model — reaches the path layer. See `isSafeArtifactId`.
*/
private rehydrate;
}