UNPKG

@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
/** * 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; }