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

265 lines (264 loc) • 11.3 kB
/** * Local structural types for the optional @juspay/hippocampus integration. * * These mirror the public shapes that ship with @juspay/hippocampus's * `dist/types.d.ts` so NeuroLink's public type surface stays compatible * for consumers that already configure memory, while the runtime package * itself becomes an optional peer dependency. The previous setup (a hard * value import of @juspay/hippocampus) made pnpm pull a registry copy of * @juspay/neurolink to satisfy Hippocampus's peer, which transitively * dragged @ai-sdk/google + @ai-sdk/google-vertex into the production * dependency graph. * * Naming: * - Hippocampus's own `StorageType` and `RedisStorageConfig` collide with * NeuroLink's in-house Redis manager types in `common.ts` / * `conversation.ts`. To satisfy the `unique-type-names` ESLint rule, * the storage variants get a `Memory*` prefix here. * - `HippocampusMemory` (consumer-facing) and `StorageConfig` (legacy * re-export) keep their original public names — only their definitions * move from `import("@juspay/hippocampus").Foo` to local structural form. */ import type { TokenUsage } from "./analytics.js"; import type { AdditionalMemoryUser } from "./generate.js"; import type { NeurolinkCredentials } from "./providers.js"; export type MemorySqliteStorageConfig = { type: "sqlite"; /** Path to SQLite file. Default: ./data/hippocampus.sqlite */ path?: string; }; export type MemoryRedisStorageConfig = { type: "redis"; host?: string; port?: number; password?: string; db?: number; keyPrefix?: string; ttl?: number; }; export type MemoryS3StorageConfig = { type: "s3"; bucket: string; prefix?: string; }; export type MemoryCustomStorageConfig = { type: "custom"; onGet: (ownerId: string) => Promise<string | null>; onSet: (ownerId: string, memory: string) => Promise<void>; onDelete: (ownerId: string) => Promise<void>; onClose?: () => Promise<void>; }; /** * Storage configuration accepted by the optional Hippocampus client. * Re-exported with the legacy `StorageConfig` name from `conversation.ts` * to preserve the existing public type surface. */ export type HippocampusStorageConfig = MemorySqliteStorageConfig | MemoryRedisStorageConfig | MemoryS3StorageConfig | MemoryCustomStorageConfig; /** Per-call options accepted by `Hippocampus.add`. */ export type HippocampusAddOptions = { prompt?: string; maxWords?: number; }; /** * The exact request shape Hippocampus's condenser sends to `generate()` * (`@juspay/hippocampus` `src/client.ts`, the `neurolink.generate({...})` * call inside `add()`). A full `NeuroLink` instance satisfies this * structurally; so does any host object that can answer a plain text prompt. */ export type HippocampusCondenserGenerateOptions = { input: { text: string; }; provider?: string; model?: string; temperature?: number; disableTools?: boolean; }; /** The only field Hippocampus reads back from the condensation call. */ export type HippocampusCondenserResult = { content?: string; }; /** * Minimal `generate()`-bearing object Hippocampus can use for condensation * instead of constructing its own bare `new NeuroLink()`. */ export type HippocampusNeurolinkLike = { generate: (options: HippocampusCondenserGenerateOptions) => Promise<HippocampusCondenserResult>; }; /** * Condenser settings forwarded to Hippocampus. * * `provider` / `model` / `temperature` select the condensation model. * `credentials` and `instance` are read by `@juspay/hippocampus` ≥0.2.0; * the peer floor is 0.2.1, which also substitutes the condensation * placeholders literally (user content containing `$&` no longer corrupts * the prompt). NeuroLink always fills `instance` itself — a dedicated * child instance that carries this instance's `credentials` — unless the * host supplies one, so condensation stops depending on provider keys being * present in `process.env`. */ export type HippocampusNeurolinkConfig = { provider?: string; model?: string; temperature?: number; /** * Credentials for the condenser's own NeuroLink instance. Defaults to the * parent `new NeuroLink({ credentials })` value. */ credentials?: NeurolinkCredentials; /** * Host-managed condenser. When set, NeuroLink does not build a child * instance and passes this object through untouched. */ instance?: HippocampusNeurolinkLike; }; /** Constructor config accepted by the Hippocampus class. */ export type HippocampusConfig = { storage?: HippocampusStorageConfig; prompt?: string; neurolink?: HippocampusNeurolinkConfig; maxWords?: number; }; /** * One completed turn as seen by the memory write hooks. `usage`, * `finishReason` and `toolsUsed` are best-effort: the generate path has the * full result, the stream path only knows the provider, the accumulated * text and this request's own stream result's tool names. */ export type MemoryTurn = { /** The caller's original prompt, before memory context was prepended. */ prompt: string; /** The assistant's final text, trimmed. */ response: string; /** Primary memory owner — `context.userId`. */ userId: string; /** `context.sessionId`, when the call carried one. */ sessionId?: string; provider?: string; model?: string; /** Names of tools that ran during the turn. */ toolsUsed?: string[]; /** Token usage — generate path only. */ usage?: TokenUsage; /** Provider finish reason — generate path only. */ finishReason?: string; }; /** * Gate that decides whether a turn is written to memory at all. Runs inside * the deferred background write, never on the response path. Returning * `false` skips every `add()` for the turn (primary owner and * `additionalUsers`). A thrown error is logged and treated as `false`. */ export type MemoryShouldWriteHook = (turn: MemoryTurn) => boolean | Promise<boolean>; /** * Transform (or veto) the exact text handed to `Hippocampus.add()`. Receives * the default `"User: …\nAssistant: …"` rendering; return a replacement * string, or `null` to skip the write. A thrown error is logged and the * write is skipped — a missed memory is recoverable, a polluted condensed * summary is not. */ export type MemoryBeforeStoreHook = (content: string, turn: MemoryTurn) => string | null | Promise<string | null>; /** * Write-side hooks accepted both per call (`generate({ memory })` / * `stream({ memory })`) and on the instance * (`conversationMemory.memory`). When both are set for the same hook, the * per-call one wins for that call. */ export type MemoryWriteHooks = { shouldWrite?: MemoryShouldWriteHook; onBeforeStore?: MemoryBeforeStoreHook; }; /** * Per-call `memory` block shared by `GenerateOptions` and `StreamOptions`. * * Overrides the instance-level memory behaviour for one call. All flags * default to `true` when the instance memory SDK is enabled; when it is * disabled this block has no effect. */ export type MemoryCallOptions = MemoryWriteHooks & { /** Master toggle for this call. When false, both read and write are skipped. Defaults to true. */ enabled?: boolean; /** Whether to read condensed memory and prepend to prompt. Defaults to true. */ read?: boolean; /** Whether to write (add/condense) the conversation into memory after completion. Defaults to true. */ write?: boolean; /** * Additional users whose memory should be retrieved/stored alongside the primary user. * Each entry can override the condensation prompt and maxWords for that user. * Primary user is still determined by context.userId. */ additionalUsers?: AdditionalMemoryUser[]; /** * Condensation prompt for the primary owner on this call. Precedence: * per-call > instance `conversationMemory.memory.prompt` > Hippocampus * default. Must contain `{{OLD_MEMORY}}` and `{{NEW_CONTENT}}`; a template * missing either is logged and the instance prompt is used instead. An * empty or whitespace-only string counts as unset. */ prompt?: string; /** Max words for the primary owner's condensed memory on this call. */ maxWords?: number; }; /** Placeholder names a condensation prompt template can carry. */ export type CondensationPlaceholder = "OLD_MEMORY" | "NEW_CONTENT" | "MAX_WORDS"; /** * Result of `validateCondensationPrompt()`. `missing` lists every absent * placeholder; `fatal` is the subset whose absence breaks memory * (`OLD_MEMORY`: each turn overwrites the summary; `NEW_CONTENT`: memory * never grows). A missing `MAX_WORDS` only loses the word cap. */ export type CondensationPromptValidation = { valid: boolean; missing: CondensationPlaceholder[]; fatal: CondensationPlaceholder[]; }; /** * Subset of the @juspay/hippocampus client surface that NeuroLink core * actually calls. Defining this locally lets the initializer / SDK code * avoid a value or even a type import from the optional package. */ export type HippocampusLike = { add: (ownerId: string, content: string, options?: HippocampusAddOptions) => Promise<string>; get: (ownerId: string) => Promise<string | null>; delete: (ownerId: string) => Promise<void>; close: () => Promise<void>; }; /** Builds a Hippocampus-compatible client from the config NeuroLink assembled. */ export type HippocampusClientFactory = (config: HippocampusConfig) => HippocampusLike; /** * Consumer-facing memory config. The `enabled` flag toggles activation; the * `HippocampusConfig` part is passed to the Hippocampus constructor when the * optional package is installed. The remaining fields are NeuroLink-side and * never reach Hippocampus. */ export type HippocampusMemory = HippocampusConfig & MemoryWriteHooks & { enabled?: boolean; /** * Host-managed Hippocampus client (or any object with the same * `add/get/delete/close` surface). When set, NeuroLink skips loading and * constructing `@juspay/hippocampus` and uses this instance directly. * `add()` and `get()` are what core calls and must both be functions; * a client missing either disables memory with an `error` log. * * As a factory it receives the `HippocampusConfig` NeuroLink assembled — * including the credentialed condenser under `neurolink.instance` — so a * host can construct its own client (a subclass, a different version, a * test double) from exactly what `new Hippocampus(config)` would get. */ client?: HippocampusLike | HippocampusClientFactory; /** * When true, a condensation prompt template (instance `prompt` or * `HC_CONDENSATION_PROMPT`) missing `{{OLD_MEMORY}}` or `{{NEW_CONTENT}}` * makes the constructor throw instead of the default disable-and-log * (at `error`). An empty or whitespace-only template counts as unset. */ strictPrompt?: boolean; }; /** * Shape of the dynamically-required `@juspay/hippocampus` module surface * that NeuroLink's lazy initializer reaches for. Only the constructor is * surfaced here; the rest of the module is irrelevant to core. */ export type HippocampusModule = { Hippocampus: new (config?: HippocampusConfig) => HippocampusLike; };