/** * VelesDB TypeScript SDK - Core Type Definitions * * Collection, configuration, and basic document types. * @packageDocumentation */ /** Supported distance metrics for vector similarity */ type DistanceMetric = 'cosine' | 'euclidean' | 'dot' | 'hamming' | 'jaccard'; /** Storage mode for vector quantization */ type StorageMode = 'full' | 'sq8' | 'binary' | 'pq' | 'rabitq'; /** Search quality preset controlling recall vs speed tradeoff. */ type SearchQuality = 'fast' | 'balanced' | 'accurate' | 'perfect' | 'autotune' | `custom:${number}` | `adaptive:${number}:${number}`; /** Backend type for VelesDB connection */ type BackendType = 'wasm' | 'rest'; /** * Point ID accepted by the velesdb-server REST API (`u64`). * * Ids within the JS safe-integer range are numbers; decimal-string ids above * `Number.MAX_SAFE_INTEGER` (2^53-1) stay verbatim strings so the full u64 * range survives the JavaScript boundary without precision loss (the server * deserialises both forms since #1004). */ type RestPointId = number | string; /** Configuration options for VelesDB client */ interface VelesDBConfig { /** Backend type: 'wasm' for browser/Node.js, 'rest' for server */ backend: BackendType; /** REST API URL (required for 'rest' backend) */ url?: string; /** API key for authentication (optional) */ apiKey?: string; /** Request timeout in milliseconds (default: 30000) */ timeout?: number; } /** Collection type */ type CollectionType = 'vector' | 'metadata_only' | 'graph'; /** HNSW index parameters for collection creation */ interface HnswParams { /** Number of bi-directional links per node (M parameter) */ m?: number; /** Size of dynamic candidate list during construction */ efConstruction?: number; /** Maximum number of elements in the index */ maxElements?: number; /** Storage mode for vector quantization */ storageMode?: StorageMode; /** Alpha parameter for HNSW construction */ alpha?: number; } /** * Deferred indexing configuration (`velesdb_core::collection::streaming::DeferredIndexerConfig`). * * When enabled, inserts are buffered in memory and batch-merged into the * HNSW index once the buffer reaches `mergeThreshold` or once the oldest * buffered vector is older than `maxBufferAgeMs`. Trades insert latency * for throughput. */ interface DeferredIndexerOptions { /** Whether deferred indexing is enabled (default: false). */ enabled?: boolean; /** Number of buffered vectors that triggers a merge into HNSW. */ mergeThreshold?: number; /** Max age (ms) of the oldest buffered vector before a time-based merge. */ maxBufferAgeMs?: number; } /** * Async index builder configuration (`velesdb_core::collection::streaming::AsyncIndexBuilderConfig`). * * Enables the parallel segment-based `AsyncIndexBuilder` for bulk inserts * (Issue #488 -- Bulk Insert V2). Used when the collection is known to * receive large bulk loads where the extra segment coordination cost is * amortised over millions of inserts. */ interface AsyncIndexBuilderOptions { /** Buffered vector count that triggers a build (default: 10_000). */ mergeThreshold?: number; /** Number of segments for parallel construction (default: num_cpus). */ segmentCount?: number; } /** Collection configuration */ interface CollectionConfig { /** Vector dimension (e.g., 768 for BERT, 1536 for GPT). Required for vector collections. */ dimension?: number; /** Distance metric (default: 'cosine') */ metric?: DistanceMetric; /** Storage mode for vector quantization (default: 'full') * - 'full': Full f32 precision (3 KB/vector for 768D) * - 'sq8': 8-bit scalar quantization, 4x memory reduction (~1% recall loss) * - 'binary': 1-bit binary quantization, 32x memory reduction (edge/IoT) * - 'pq': Product quantization (requires training via `trainPq`) * - 'rabitq': RaBitQ quantization (binary + rescoring) */ storageMode?: StorageMode; /** Collection type: 'vector' (default) or 'metadata_only' */ collectionType?: CollectionType; /** Optional collection description */ description?: string; /** Optional HNSW parameters for index tuning */ hnsw?: HnswParams; /** * PQ rescore oversampling factor (quantised storage modes only). * * The search pipeline fetches `max(k * factor, k + 32)` candidates from * HNSW and rescores them with full-precision ADC. Default is `4`. * Setting `0` disables rescoring (fastest, lowest recall). */ pqRescoreOversampling?: number; /** Deferred indexing buffer configuration (US-366). */ deferredIndexing?: DeferredIndexerOptions; /** Parallel async index builder configuration (Issue #488). */ asyncIndexBuilder?: AsyncIndexBuilderOptions; } /** Collection metadata */ interface Collection { /** Collection name */ name: string; /** Vector dimension */ dimension: number; /** Distance metric */ metric: DistanceMetric; /** Storage mode */ storageMode?: StorageMode; /** Number of vectors */ count: number; /** Creation timestamp */ createdAt?: Date; } /** Sparse vector: mapping from term/dimension index to weight */ type SparseVector = Record; /** Vector document to upsert */ interface VectorDocument { /** Unique identifier */ id: string | number; /** Vector data */ vector: number[] | Float32Array; /** Optional payload/metadata */ payload?: Record; /** Optional sparse vector for hybrid search */ sparseVector?: SparseVector; } /** PQ (Product Quantization) training options */ interface PqTrainOptions { /** Number of subquantizers (default: 8) */ m?: number; /** Number of centroids per subquantizer (default: 256) */ k?: number; /** Enable Optimized Product Quantization (default: false) */ opq?: boolean; } /** * VelesDB Filter DSL * * Typed mirror of `velesdb_core::filter::Condition` (20 operators). * Provides a fluent builder API (`f.*`) for ergonomic filter construction * and accepts raw `Record` objects for backward compatibility * with pre-v1.13 code. * * @example Typed builder * ```typescript * import { f } from '@wiscale/velesdb-sdk'; * * const filter = f.and([ * f.eq('category', 'tech'), * f.gte('price', 100), * f.not(f.isNull('author')), * ]); * const results = await db.search('docs', query, { filter }); * ``` * * @example Legacy JSON (backward-compat, no compile-time checking) * ```typescript * const filter = { * condition: { type: 'eq', field: 'category', value: 'tech' } * }; * const results = await db.search('docs', query, { filter }); * ``` * * @packageDocumentation */ /** JSON value accepted by filter operators (mirror of `serde_json::Value`). */ type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue; }; /** * Comparison operators used by `GeoDistance`. * * Mirrors `velesdb_core::velesql::ast::condition::CompareOp` which * serializes with default (PascalCase) serde representation. */ type CompareOp = 'Eq' | 'NotEq' | 'Gt' | 'Gte' | 'Lt' | 'Lte'; /** * Discriminated union matching `velesdb_core::filter::Condition`. * * The wire format uses `{"type": "", ...}` as produced * by `#[serde(tag = "type", rename_all = "snake_case")]` on the Rust enum. * * 20 variants total — any change must stay in lock-step with the Rust source. */ type Condition = { type: 'eq'; field: string; value: JsonValue; } | { type: 'neq'; field: string; value: JsonValue; } | { type: 'gt'; field: string; value: JsonValue; } | { type: 'gte'; field: string; value: JsonValue; } | { type: 'lt'; field: string; value: JsonValue; } | { type: 'lte'; field: string; value: JsonValue; } | { type: 'in'; field: string; values: JsonValue[]; } | { type: 'contains'; field: string; value: string; } | { type: 'is_null'; field: string; } | { type: 'is_not_null'; field: string; } | { type: 'and'; conditions: Condition[]; } | { type: 'or'; conditions: Condition[]; } | { type: 'not'; condition: Condition; } | { type: 'like'; field: string; pattern: string; } | { type: 'ilike'; field: string; pattern: string; } | { type: 'array_contains'; field: string; value: JsonValue; } | { type: 'array_contains_any'; field: string; values: JsonValue[]; } | { type: 'array_contains_all'; field: string; values: JsonValue[]; } | { type: 'geo_distance'; field: string; lat: number; lng: number; operator: CompareOp; threshold: number; } | { type: 'geo_bbox'; field: string; lat_min: number; lng_min: number; lat_max: number; lng_max: number; }; /** * A filter for metadata-based search refinement. * * Mirrors `velesdb_core::filter::Filter` which wraps a root `Condition`. */ interface Filter { condition: Condition; } /** * Filter parameter type accepted by SDK methods. * * - `Filter`: typed filter produced by the `f.*` builders. **Recommended.** * - `Record`: raw JSON object for backward compatibility * with pre-v1.13 code. The payload is forwarded verbatim to the server. */ type FilterInput = Filter | Record; /** * Type guard narrowing a `FilterInput` to the typed `Filter` shape. * * Returns `true` only when the value has a `condition` property that is * itself a non-null object. Does NOT validate the inner condition shape * — use TypeScript's compile-time checking for that. */ declare function isTypedFilter(input: FilterInput): input is Filter; /** * Normalizes a filter input to the wire format expected by velesdb-server. * * The SDK never rewrites filter payloads — it forwards them verbatim. This * helper exists to keep backend code agnostic of whether the caller passed * a typed `Filter` or a legacy `Record`. * * Passing `undefined` returns `undefined`, signalling the server should * apply no filter. */ declare function normalizeFilter(input: FilterInput): Record; declare function normalizeFilter(input: undefined): undefined; declare function normalizeFilter(input: FilterInput | undefined): Record | undefined; /** * Fluent filter builder. * * Each method returns a new `Filter` whose root `condition` matches the * wire format expected by `velesdb-server`. Builders do not mutate inputs: * arrays passed to `in`, `arrayContainsAny`, `arrayContainsAll`, `and`, `or` * are copied before being wrapped. */ declare const f: { /** `field == value` */ readonly eq: (field: string, value: JsonValue) => Filter; /** `field != value` */ readonly neq: (field: string, value: JsonValue) => Filter; /** `field > value` */ readonly gt: (field: string, value: JsonValue) => Filter; /** `field >= value` */ readonly gte: (field: string, value: JsonValue) => Filter; /** `field < value` */ readonly lt: (field: string, value: JsonValue) => Filter; /** `field <= value` */ readonly lte: (field: string, value: JsonValue) => Filter; /** `field IN (values...)` — the values list is copied. */ readonly in: (field: string, values: JsonValue[]) => Filter; /** Substring containment: `field LIKE '%value%'` (case-sensitive). */ readonly contains: (field: string, value: string) => Filter; /** `field IS NULL` */ readonly isNull: (field: string) => Filter; /** `field IS NOT NULL` */ readonly isNotNull: (field: string) => Filter; /** SQL LIKE pattern matching (case-sensitive). Supports `%` and `_`. */ readonly like: (field: string, pattern: string) => Filter; /** SQL ILIKE pattern matching (case-insensitive). */ readonly ilike: (field: string, pattern: string) => Filter; /** `value IN field` (field must be an array). */ readonly arrayContains: (field: string, value: JsonValue) => Filter; /** At least one of `values` is present in the array field. */ readonly arrayContainsAny: (field: string, values: JsonValue[]) => Filter; /** Every value in `values` is present in the array field. */ readonly arrayContainsAll: (field: string, values: JsonValue[]) => Filter; /** Haversine distance comparison: `distance(field, (lat, lng)) threshold`. */ readonly geoDistance: (field: string, lat: number, lng: number, operator: CompareOp, threshold: number) => Filter; /** Bounding-box containment: point field falls inside `[lat_min, lat_max] x [lng_min, lng_max]`. */ readonly geoBbox: (field: string, bounds: { lat_min: number; lng_min: number; lat_max: number; lng_max: number; }) => Filter; /** `field NOT IN (values...)` — shorthand for `not(in(field, values))`. */ readonly notIn: (field: string, values: JsonValue[]) => Filter; /** `field BETWEEN low AND high` — shorthand for `and([gte(field, low), lte(field, high)])`. */ readonly between: (field: string, low: JsonValue, high: JsonValue) => Filter; /** Logical AND — the filters list is copied and flattened to root conditions. */ readonly and: (filters: Filter[]) => Filter; /** Logical OR — the filters list is copied and flattened to root conditions. */ readonly or: (filters: Filter[]) => Filter; /** Logical NOT — wraps a single filter. */ readonly not: (filter: Filter) => Filter; }; /** * VelesDB TypeScript SDK - Search Type Definitions * * Search options, results, and fusion types. * @packageDocumentation */ /** * Options for `db.sparseSearchNamed()` — **pure sparse** query against a * named sparse index (issue #380). * * Use this when you have only a sparse vector and want to query a specific * named sparse index directly. The query carries no dense component. * * For **dense + sparse hybrid** against a named index, use * `db.search(..., { sparseVector, sparseIndexName })` instead * (see {@link SearchOptions.sparseIndexName}). * * **Backend support:** REST only. The WASM backend has no concept of named * sparse indexes; this method throws `wasmNotSupported` on WASM. */ interface SparseSearchNamedOptions { /** Number of results to return (default: 10) */ k?: number; /** Filter expression */ filter?: FilterInput; /** Optional dense vector to combine with sparse for hybrid named search */ vector?: number[] | Float32Array; /** Search quality preset */ quality?: SearchQuality; } /** Search options */ interface SearchOptions { /** Number of results to return (default: 10) */ k?: number; /** Filter expression (optional). Accepts typed `Filter` (recommended) or legacy raw JSON. */ filter?: FilterInput; /** Include vectors in results (default: false) */ includeVectors?: boolean; /** Optional sparse vector for hybrid sparse+dense search */ sparseVector?: SparseVector; /** * Named sparse index to combine with the dense query for **hybrid** search * (when the collection has multiple sparse indexes). When omitted, the * default sparse index is used. * * For a **pure sparse** query against a named index (no dense vector), * call `db.sparseSearchNamed()` instead — see {@link SparseSearchNamedOptions}. * * **Backend support:** REST only. The WASM backend silently ignores this * field and uses the collection's single sparse index regardless. */ sparseIndexName?: string; /** Search quality preset (default: 'balanced'). */ quality?: SearchQuality; } /** Fusion strategy for multi-query search */ type FusionStrategy = 'rrf' | 'average' | 'maximum' | 'weighted' | 'relative_score'; /** Multi-query search options */ interface MultiQuerySearchOptions { /** Number of results to return (default: 10) */ k?: number; /** Fusion strategy (default: 'rrf') */ fusion?: FusionStrategy; /** Fusion parameters */ fusionParams?: { /** RRF k parameter (default: 60) */ k?: number; /** Weighted fusion: average weight (default: 0.6) */ avgWeight?: number; /** Weighted fusion: max weight (default: 0.3) */ maxWeight?: number; /** Weighted fusion: hit weight (default: 0.1) */ hitWeight?: number; /** Relative score fusion: dense vector weight (default: 0.5) */ denseWeight?: number; /** Relative score fusion: sparse vector weight (default: 0.5) */ sparseWeight?: number; }; /** Filter expression (optional). Accepts typed `Filter` (recommended) or legacy raw JSON. */ filter?: FilterInput; } /** Search result */ interface SearchResult { /** Document ID */ id: string | number; /** Similarity score */ score: number; /** Document payload (if requested) */ payload?: Record; /** Vector data (if includeVectors is true) */ vector?: number[]; } /** * VelesDB TypeScript SDK - Graph Type Definitions * * Knowledge graph types: edges, traversal, degree, graph collections. * @packageDocumentation */ /** Graph node/edge ID. Large u64 IDs may be returned as strings to preserve precision. */ type GraphNodeId = number | string; /** Graph edge representing a relationship between nodes */ interface GraphEdge { /** Unique edge ID */ id: GraphNodeId; /** Source node ID */ source: GraphNodeId; /** Target node ID */ target: GraphNodeId; /** Edge label (relationship type, e.g., "KNOWS", "FOLLOWS") */ label: string; /** Edge properties */ properties?: Record; } /** * Request to add an edge to the graph. * Structurally identical to GraphEdge -- kept as a named alias for * semantic clarity (input vs stored model). */ type AddEdgeRequest = GraphEdge; /** Response containing edges */ interface EdgesResponse { /** List of edges */ edges: GraphEdge[]; /** Total count of edges returned */ count: number; } /** Options for querying edges */ interface GetEdgesOptions { /** Filter by edge label */ label?: string; } /** Request for graph traversal (EPIC-016 US-050) */ interface TraverseRequest { /** Source node ID to start traversal from */ source: GraphNodeId; /** Traversal strategy: 'bfs' or 'dfs' */ strategy?: 'bfs' | 'dfs'; /** Maximum traversal depth */ maxDepth?: number; /** Maximum number of results to return */ limit?: number; /** Optional cursor for pagination */ cursor?: string; /** Filter by relationship types (empty = all types) */ relTypes?: string[]; } /** Request for multi-source parallel BFS traversal */ interface TraverseParallelRequest { /** Source node IDs to start traversal from */ sources: GraphNodeId[]; /** Maximum traversal depth */ maxDepth?: number; /** Maximum number of results to return */ limit?: number; /** Filter by relationship types (empty = all types) */ relTypes?: string[]; } /** A single traversal result item */ interface TraversalResultItem { /** Target node ID reached */ targetId: GraphNodeId; /** Depth of traversal (number of hops from source) */ depth: number; /** Path taken (list of edge IDs) */ path: GraphNodeId[]; } /** Statistics from traversal operation */ interface TraversalStats { /** Number of nodes visited */ visited: number; /** Maximum depth reached */ depthReached: number; } /** Response from graph traversal */ interface TraverseResponse { /** List of traversal results */ results: TraversalResultItem[]; /** Cursor for next page (if applicable) */ nextCursor?: string; /** Whether more results are available */ hasMore: boolean; /** Traversal statistics */ stats: TraversalStats; } /** Response for node degree query */ interface DegreeResponse { /** Number of incoming edges */ inDegree: number; /** Number of outgoing edges */ outDegree: number; } /** Request body for POST /collections/{name}/relations */ interface RelateRequest { /** Source point ID */ source: GraphNodeId; /** Target point ID */ target: GraphNodeId; /** Relationship type label (e.g. "KNOWS", "RELATED_TO") */ relType: string; /** Optional edge properties */ properties?: Record; } /** Response from POST /collections/{name}/relations */ interface RelateResponse { /** Allocated edge ID */ edgeId: GraphNodeId; } /** A single outgoing relation edge */ interface RelationEdge { /** Edge ID */ id: GraphNodeId; /** Source point ID */ source: GraphNodeId; /** Target point ID */ target: GraphNodeId; /** Relationship type label */ relType: string; /** Edge properties */ properties?: Record; } /** Response from GET /collections/{name}/points/{id}/relations */ interface RelationsResponse { /** Outgoing relation edges */ edges: RelationEdge[]; /** Total count */ count: number; } /** Schema mode for graph collections */ type GraphSchemaMode = 'schemaless' | 'strict'; /** Graph collection configuration */ interface GraphCollectionConfig { /** Optional embedding dimension for node vectors */ dimension?: number; /** Distance metric for embeddings (default: 'cosine') */ metric?: DistanceMetric; /** Schema mode (default: 'schemaless') */ schemaMode?: GraphSchemaMode; } /** * VelesDB TypeScript SDK - Agent Memory Type Definitions * * Semantic, episodic, and procedural memory types. * @packageDocumentation */ /** Semantic memory entry */ interface SemanticEntry { /** * Unique fact ID. * * `string | number` is accepted as a convenience (a string must be a decimal * integer). Ids must be non-negative integers within the JS safe-integer * range (0..2^53-1): the REST wire transmits point ids as JSON numbers, so * out-of-range ids are rejected (not silently truncated). */ id: string | number; /** Fact text content */ text: string; /** Embedding vector */ embedding: number[]; /** Optional metadata */ metadata?: Record; } /** Episodic memory event */ interface EpisodicEvent { /** * Optional caller-provided event ID. When omitted, a monotonic id is * generated. `string | number` is accepted as a convenience; ids must be * non-negative integers within the JS safe-integer range (0..2^53-1) because * the REST wire transmits them as JSON numbers, and out-of-range ids are * rejected (not silently truncated). */ id?: string | number; /** Event type identifier */ eventType: string; /** * Event timestamp as a NUMERIC unix time in **seconds**. * * Mirrors the core episodic store, which persists a numeric `timestamp` * that feeds `recent(since)` / `older_than(before)`. When omitted it * defaults to the current unix-seconds value (`floor(Date.now() / 1000)`). */ timestamp?: number; /** Event data */ data: Record; /** Embedding vector */ embedding: number[]; /** Optional metadata */ metadata?: Record; } /** Procedural memory pattern */ interface ProceduralPattern { /** * Optional caller-provided pattern ID. When omitted, a monotonic id is * generated. `string | number` is accepted as a convenience; ids must be * non-negative integers within the JS safe-integer range (0..2^53-1) because * the REST wire transmits them as JSON numbers, and out-of-range ids are * rejected (not silently truncated). */ id?: string | number; /** Procedure name */ name: string; /** Ordered steps */ steps: string[]; /** * Embedding vector for the pattern. * * Required so that `matchProceduralPatterns` (a vector search) can * recall the pattern — a point stored without a vector is invisible * to similarity search. */ embedding: number[]; /** Optional metadata */ metadata?: Record; } /** A single episodic event recalled by timestamp. */ interface EpisodicRecord { /** Point id as a string (u64 precision preserved). */ id: string; /** Numeric unix-seconds timestamp. */ timestamp: number; /** Full point payload (includes `event_type`, caller data/metadata). */ payload: Record; } /** Agent memory configuration */ interface AgentMemoryConfig { /** Embedding dimension (default: 384) */ dimension?: number; } /** * VelesDB TypeScript SDK - Query & Introspection Type Definitions * * VelesQL query types, scroll, column stats, EXPLAIN, and collection sanity. * @packageDocumentation */ /** Request parameters for cursor-based scroll pagination. */ interface ScrollRequest { /** Cursor position to resume from. Omit to start from beginning. */ cursor?: string | number; /** Number of points per page (1-10000, default 100). */ batchSize?: number; /** Optional filter expression. Accepts typed `Filter` (recommended) or legacy raw JSON. */ filter?: FilterInput; } /** Response from scroll pagination. */ interface ScrollResponse { /** Points in this page. */ points: Array<{ id: string | number; vector?: number[]; payload?: Record; }>; /** Cursor for next page, or null if no more results. */ nextCursor: string | number | null; } /** Per-column statistics including histogram metadata. */ interface ColumnStatsDetail { name: string; nullCount: number; distinctCount: number; minValue: unknown; maxValue: unknown; avgSizeBytes: number; histogramBuckets: number | null; histogramStale: boolean | null; } /** Actual execution statistics from EXPLAIN ANALYZE. */ interface ActualStats { actualRows: number; actualTimeMs: number; loops: number; nodesVisited: number; edgesTraversed: number; } /** * Per-node **estimated** execution statistics from EXPLAIN ANALYZE. * * All values are synthetic heuristics derived from the plan-global * `actualTimeMs` -- they are NOT individually measured per node. * Field names keep the `actual` prefix for API stability; check * the `estimated` flag to distinguish heuristic values from future * instrumented measurements. */ interface NodeStats { nodeLabel: string; /** Estimated wall-clock time for this node (ms). */ actualTimeMs: number; /** Estimated rows entering this node. */ actualRowsIn: number; /** Estimated rows leaving this node. */ actualRowsOut: number; loops: number; /** When true, all values are heuristic estimates, not measured. */ estimated: boolean; } /** Collection statistics response */ interface CollectionStatsResponse { totalPoints: number; totalSizeBytes: number; rowCount: number; deletedCount: number; avgRowSizeBytes: number; payloadSizeBytes: number; lastAnalyzedEpochMs: number; columnStats?: Record; } /** Collection configuration response. Mirrors `velesdb_core::api_types::CollectionConfigResponse`. */ interface CollectionConfigResponse { name: string; dimension: number; metric: DistanceMetric; storageMode: StorageMode; pointCount: number; metadataOnly: boolean; graphSchema?: Record; embeddingDimension?: number; /** * On-disk schema version. Increments when the persisted `config.json` * format changes in a way older `VelesDB` versions cannot safely read. */ schemaVersion?: number; /** PQ rescore oversampling factor -- see `CollectionConfig.pqRescoreOversampling`. */ pqRescoreOversampling?: number; /** Persisted HNSW parameters when customised at create time (raw server JSON). */ hnswParams?: Record; /** Deferred indexing configuration (`null` / absent when the feature is disabled for this collection). */ deferredIndexing?: Record; /** Async index builder configuration (`null` / absent when the feature is disabled for this collection). */ asyncIndexBuilder?: Record; } /** VelesQL query options */ interface QueryOptions { /** Timeout in milliseconds (default: 30000) */ timeoutMs?: number; /** Enable streaming response */ stream?: boolean; } /** * Query result row from VelesQL query. * * Shape depends on the SELECT clause: * - `SELECT *` -> `{id, field1, field2, ...}` (no vector) * - `SELECT col1, col2` -> `{col1, col2}` * - `SELECT similarity() AS score, title` -> `{score, title}` */ type QueryResult = Record; /** Query execution statistics */ interface QueryStats { /** Execution time in milliseconds */ executionTimeMs: number; /** Execution strategy used */ strategy: string; /** Number of nodes scanned */ scannedNodes: number; } /** Full query response with results and stats */ interface QueryResponse { /** Query results */ results: QueryResult[]; /** Execution statistics */ stats: QueryStats; } /** Aggregation query response from VelesQL (`GROUP BY`, `COUNT`, `SUM`, etc.). */ interface AggregationQueryResponse { /** Aggregation result payload as returned by server. */ result: Record | unknown[]; /** Execution statistics */ stats: QueryStats; } /** Unified response type for `query()` (rows, aggregation, or DDL). * * DDL statements (CREATE, DROP) and mutations (INSERT EDGE, DELETE) return * a standard `QueryResponse` with an empty `results` array. */ type QueryApiResponse = QueryResponse | AggregationQueryResponse; /** Query explain request/response metadata */ interface ExplainPlanStep { step: number; operation: string; description: string; estimatedRows: number | null; estimationMethod: string | null; } interface ExplainCost { usesIndex: boolean; indexName: string | null; selectivity: number; complexity: string; } interface ExplainFeatures { hasVectorSearch: boolean; hasFilter: boolean; hasOrderBy: boolean; hasGroupBy: boolean; hasAggregation: boolean; hasJoin: boolean; hasFusion: boolean; limit: number | null; offset: number | null; } interface ExplainResponse { query: string; queryType: string; collection: string; plan: ExplainPlanStep[]; estimatedCost: ExplainCost; features: ExplainFeatures; actualStats?: ActualStats | null; nodeStats?: NodeStats[] | null; } interface CollectionSanityChecks { hasVectors: boolean; searchReady: boolean; dimensionConfigured: boolean; } interface CollectionSanityDiagnostics { searchRequestsTotal: number; dimensionMismatchTotal: number; emptySearchResultsTotal: number; filterParseErrorsTotal: number; } interface CollectionSanityResponse { collection: string; dimension: number; metric: string; pointCount: number; isEmpty: boolean; checks: CollectionSanityChecks; diagnostics: CollectionSanityDiagnostics; hints: string[]; } /** * VelesDB TypeScript SDK - Index Management Type Definitions * * Property index types for secondary indexes. * @packageDocumentation */ /** Index type for property indexes */ type IndexType = 'hash' | 'range'; /** Index information */ interface IndexInfo { /** Node label (e.g., "Person") */ label: string; /** Property name (e.g., "email") */ property: string; /** Index type: 'hash' for O(1) equality, 'range' for O(log n) range queries */ indexType: IndexType; /** Number of unique values indexed (for hash indexes) */ cardinality: number; /** Memory usage in bytes */ memoryBytes: number; } /** Options for creating an index */ interface CreateIndexOptions { /** Node label to index */ label: string; /** Property name to index */ property: string; /** Index type: 'hash' (default) or 'range' */ indexType?: IndexType; } /** * Mutable collection settings toggled at runtime via `ALTER COLLECTION`. * * Used by {@link VelesDB.alterCollection}. Only the keys you set are * emitted into the `SET(...)` clause. */ interface AlterCollectionOptions { /** * Enable/disable automatic index rebuilds after writes. * Emits `auto_reindex=`. */ autoReindex?: boolean; } /** * VelesDB Backend Capability Map * * Static, per-backend description of which features the currently * connected backend supports. Callers use this to gracefully degrade * their UI / plan / workflow when a feature is not available instead * of catching a runtime `NOT_SUPPORTED` error after the fact. * * The map is **frozen at backend construction** — it does not round- * trip to the server. The REST map assumes a `velesdb-server` of the * same minor version; if the server does not ship a given feature, * the individual call will still surface a typed `VelesError` at * runtime. * * @example * ```typescript * import { VelesDB } from '@wiscale/velesdb-sdk'; * * const db = new VelesDB({ backend: 'wasm' }); * await db.init(); * * if (db.capabilities().graphTraversal) { * await db.traverseGraph('kg', { source: 1, direction: 'out' }); * } else { * // fall back to REST or a pure in-memory traversal * } * ``` * * @packageDocumentation */ /** * Capability map surfaced by `VelesDB.capabilities()`. * * Every field is a `boolean` so that callers can write * `if (caps.feature) { ... }` without `?.` chaining. A missing * backend must still expose the full set of keys with `false` * values — we prefer explicit "unsupported" over "unknown". */ interface CapabilityMap { /** Dense vector similarity search (`search`, `searchIds`, `searchBatch`). */ vectorSearch: boolean; /** BM25 full-text search (`textSearch`). */ textSearch: boolean; /** Combined dense + BM25 search (`hybridSearch`). */ hybridSearch: boolean; /** Multi-query fusion search (`multiQuerySearch`). */ multiQuerySearch: boolean; /** Sparse vector search (`sparse_vector` on the search body + hybrid sparse+dense). */ sparseSearch: boolean; /** Cursor-based scroll pagination over a collection (`scroll`). */ scroll: boolean; /** Knowledge graph edge CRUD + traversal (`addEdge`, `traverseGraph`, `traverseParallel`, `getNodeDegree`). */ graphTraversal: boolean; /** Secondary property indexes (`createIndex`, `listIndexes`, `hasIndex`, `dropIndex`). */ secondaryIndexes: boolean; /** Agent Memory SDK (semantic, episodic, procedural). */ agentMemory: boolean; /** Enable the bounded streaming-ingestion channel (`enableStreaming`). */ enableStreaming: boolean; /** Streaming insert with backpressure (`streamInsert`). */ streamInsert: boolean; /** Product quantization training (`trainPq`). */ pqTraining: boolean; /** VelesQL multi-model query + EXPLAIN (`query`, `queryExplain`). */ velesqlQuery: boolean; /** Collection introspection endpoints (`collectionSanity`, `getCollectionStats`, `analyzeCollection`, `getCollectionConfig`). */ collectionIntrospection: boolean; /** * `USING FUSION(strategy='...')` strategies the backend's query path * accepts. Empty when `velesqlQuery` is `false`. The core SQL parser * accepts `rrf`, `weighted`, `maximum`, `rsf`, `average`. */ velesqlFusionStrategies: readonly string[]; /** * `MATCH (...) RETURN ... ORDER BY ... [LIMIT n]` is honored end-to-end * (sorted, then limited) by the backend's query path. */ velesqlMatchOrderBy: boolean; /** * `ALTER COLLECTION SET(...)` is supported via the typed * {@link VelesDB.alterCollection} / {@link VelesDB.setAutoReindex} helpers. */ velesqlAlterCollection: boolean; } /** * Capability map for the REST backend — assumes a server of the * same minor version as the SDK. Every feature the SDK wraps is * advertised; individual endpoints may still surface a typed * `VelesError` at runtime if the server was built with a feature * flag disabled. */ declare const REST_CAPABILITIES: Readonly; /** * Capability map for the WASM backend. * * The WASM build ships a focused subset: the dense / text / hybrid / * multi-query search paths. Everything that relies on persistent * on-disk structures (secondary indexes, graph, streaming, PQ * training, agent memory, introspection, sparse inverted index) is * explicitly `false`. See `backends/wasm-stubs.ts` for the exact set * of `wasmNotSupported()` throw sites. * * `velesqlQuery` is `false`: `query()` only executes pure top-k NEAR * statements (`SELECT * FROM WHERE vector NEAR $param * [LIMIT n]`) and throws `NOT_SUPPORTED` for any other VelesQL clause * (WHERE predicates, JOIN, GROUP BY, MATCH, set operations, FUSION), * so full VelesQL is not advertised. */ declare const WASM_CAPABILITIES: Readonly; /** * VelesDB TypeScript SDK - Additional Endpoint Type Definitions * * Types for Sprint 2 Wave 4 endpoints: rebuild index, guardrails, * aggregate, match query, graph node operations, and graph search. * @packageDocumentation */ /** Result of `POST /collections/{name}/index/rebuild`. */ interface RebuildIndexResponse { /** Informational message from the server. */ message: string; /** Collection name. */ collection: string; /** Number of tombstoned entries compacted during rebuild. */ compactedEntries: number; } /** Guard-rails config sent to `PUT /guardrails` (partial update). */ interface GuardRailsUpdateRequest { maxDepth?: number; maxCardinality?: number; memoryLimitBytes?: number; timeoutMs?: number; rateLimitQps?: number; circuitFailureThreshold?: number; circuitRecoverySeconds?: number; } /** Guard-rails config returned by `GET /guardrails` and `PUT /guardrails`. */ interface GuardRailsConfigResponse { maxDepth: number; maxCardinality: number; memoryLimitBytes: number; timeoutMs: number; rateLimitQps: number; circuitFailureThreshold: number; circuitRecoverySeconds: number; } /** Options for `listNodes`. */ interface ListNodesResponse { /** Node IDs in insertion order (string|number to preserve u64 precision). */ nodeIds: GraphNodeId[]; /** Total count -- matches `nodeIds.length`. */ count: number; } /** Options for `getNodeEdges`. Mirrors `NodeEdgeQueryParams` on the server. */ interface GetNodeEdgesOptions { /** Edge direction: "in", "out" (default), or "both". */ direction?: 'in' | 'out' | 'both'; /** Optional label filter. */ label?: string; } /** Result of `GET /collections/{name}/graph/nodes/{id}/payload`. */ interface NodePayloadResponse { /** Node ID. */ nodeId: GraphNodeId; /** Stored payload -- `null` if no payload has been set. */ payload: Record | null; } /** Request body for `POST /collections/{name}/graph/search`. */ interface GraphSearchRequest { /** Query vector for embedding similarity. */ vector: number[] | Float32Array; /** Number of results (default: 10). */ k?: number; } /** Single result item from `graphSearch`. */ interface GraphSearchResultItem { /** Node ID. */ id: GraphNodeId; /** Similarity score. */ score: number; /** Optional node payload (mirror of `GraphSearchResultItem.payload`). */ payload?: Record | null; } /** Response of `graphSearch`. */ interface GraphSearchResponse { /** Result items ordered by score. */ results: GraphSearchResultItem[]; } /** * Options for `matchQuery`. Mirrors the extra fields accepted by * `velesdb_server::handlers::match_query::MatchQueryRequest` * beyond `query` and `params`. */ interface MatchQueryOptions { /** Query vector for `similarity()` scoring inside the MATCH clause. */ vector?: number[] | Float32Array; /** Similarity threshold (0.0-1.0). */ threshold?: number; } /** Response from `POST /collections/{name}/match`. Mirrors the Rust * `MatchQueryResponse` struct -- intentionally distinct from the * `/query` and `/aggregate` response shapes. */ interface MatchQueryResponse { /** Pattern matches returned by the MATCH clause. */ results: MatchQueryResultItem[]; /** Server-side execution time in whole milliseconds. */ tookMs: number; /** Number of result rows (matches `results.length`). */ count: number; /** Response metadata (VelesQL contract version). */ meta: { velesqlContractVersion: string; }; } /** Single row of a `MatchQueryResponse`. */ interface MatchQueryResultItem { /** Variable-binding map from the MATCH pattern. */ bindings: Record; /** Similarity score, present only when `similarity()` was used. */ score?: number; /** Traversal depth reached to produce this row. */ depth: number; /** Projected properties from the RETURN clause. */ projected: Record; } /** Options for `aggregate`. Mirrors the extra fields accepted by * `velesdb_core::api_types::QueryRequest` beyond `query` and `params`. */ interface AggregateQueryOptions { /** * Optional collection name when the query string does not carry an * explicit `FROM ` clause. */ collection?: string; } /** Response from `POST /aggregate`. Mirrors the Rust `AggregationResponse`. */ interface AggregateResponse { /** Aggregation result -- shape depends on the SELECT clause. */ result: unknown; /** Query execution time in milliseconds. */ timingMs: number; /** Response metadata. */ meta: { velesqlContractVersion: string; count: number; }; } /** * Configuration for `POST /collections/{name}/stream/enable`. * * Enables the bounded streaming-ingestion channel on a collection so that * subsequent `streamInsert` calls are accepted. Every field is optional; * omitted fields fall back to the server defaults (`bufferSize` 10000, * `batchSize` 128, `flushIntervalMs` 50). camelCase here, converted to the * snake_case wire body by the backend. */ interface StreamingConfig { /** Bounded ingestion channel capacity (server default: 10000). */ bufferSize?: number; /** Points flushed to the index per batch (server default: 128). */ batchSize?: number; /** Max milliseconds before a partial batch is flushed (server default: 50). */ flushIntervalMs?: number; } /** * Response from `POST /collections/{name}/points/stream` (NDJSON batch upsert). * * The server returns statistics about the stream processing: how many points * were inserted, how many were malformed, how many upserts failed, and how * many network errors occurred while reading the request body. */ interface StreamUpsertResponse { /** Informational message from the server. */ message: string; /** Number of points successfully upserted. */ inserted: number; /** Number of NDJSON lines that could not be parsed as a valid Point. */ malformed: number; /** Number of points where the upsert operation itself failed. */ failedUpserts: number; /** Number of HTTP body stream read errors (non-zero means truncated transfer). */ networkErrors: number; } /** Backend interface that all backends must implement */ interface IVelesDBBackend { /** Initialize the backend */ init(): Promise; /** Check if backend is initialized */ isInitialized(): boolean; /** * Return the static capability map for this backend. * * The map is frozen at backend construction -- it does NOT round-trip * to a live server. Use it to gracefully degrade UI / workflow when * a feature is not available instead of catching a runtime * `NOT_SUPPORTED` error after the fact. */ capabilities(): Readonly; /** Create a new collection */ createCollection(name: string, config: CollectionConfig): Promise; /** Delete a collection */ deleteCollection(name: string): Promise; /** Get collection info */ getCollection(name: string): Promise; /** List all collections */ listCollections(): Promise; /** Upsert (insert or replace) a single vector */ upsert(collection: string, doc: VectorDocument): Promise; /** Upsert (insert or replace) multiple vectors */ upsertBatch(collection: string, docs: VectorDocument[]): Promise; /** * Bulk upsert multiple vectors via the binary wire format (REST only). * * Encodes `(id, vector)` pairs into the deterministic VRB1 binary layout * and POSTs them as `application/octet-stream`, avoiding per-point JSON * overhead. Payloads are not carried on this path. Not supported by the * WASM backend. * * @returns the number of points the server reports as inserted. */ upsertBatchRaw(collection: string, docs: VectorDocument[]): Promise; /** Search for similar vectors */ search(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise; /** Delete a vector by ID */ delete(collection: string, id: string | number): Promise; /** Delete multiple vectors by ID in one request; returns the deleted count. */ bulkDelete(collection: string, ids: Array): Promise; /** Get a vector by ID */ get(collection: string, id: string | number): Promise; /** Search for multiple vectors in batch */ searchBatch(collection: string, searches: Array<{ vector: number[] | Float32Array; k?: number; filter?: FilterInput; /** Per-sub-request search quality preset (default: server default). */ quality?: SearchQuality; }>): Promise; /** Full-text search using BM25 */ textSearch(collection: string, query: string, options?: { k?: number; filter?: FilterInput; }): Promise; /** Hybrid search combining vector and text */ hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: { k?: number; vectorWeight?: number; filter?: FilterInput; }): Promise; /** Execute VelesQL multi-model query (EPIC-031 US-011) */ query(collection: string, queryString: string, params?: Record, options?: QueryOptions): Promise; /** Explain a VelesQL query without executing it */ queryExplain(queryString: string, params?: Record, options?: { analyze?: boolean; }): Promise; /** Scroll through collection points with cursor-based pagination */ scroll(collection: string, request?: ScrollRequest): Promise; /** Run collection sanity checks */ collectionSanity(collection: string): Promise; /** Multi-query fusion search */ multiQuerySearch(collection: string, vectors: Array, options?: MultiQuerySearchOptions): Promise; /** Multi-query fusion search returning only IDs and scores */ multiQuerySearchIds(collection: string, vectors: Array, options?: MultiQuerySearchOptions): Promise>; /** Check if collection is empty */ isEmpty(collection: string): Promise; /** Flush pending changes to disk */ flush(collection: string): Promise; /** Close/cleanup the backend */ close(): Promise; /** Create a property index for O(1) equality lookups */ createIndex(collection: string, options: CreateIndexOptions): Promise; /** List all indexes on a collection */ listIndexes(collection: string): Promise; /** Check if an index exists */ hasIndex(collection: string, label: string, property: string): Promise; /** Drop an index */ dropIndex(collection: string, label: string, property: string): Promise; /** Add an edge to the collection's knowledge graph */ addEdge(collection: string, edge: AddEdgeRequest): Promise; /** Get edges from the collection's knowledge graph */ getEdges(collection: string, options?: GetEdgesOptions): Promise; /** Traverse the graph using BFS or DFS from a source node */ traverseGraph(collection: string, request: TraverseRequest): Promise; /** Multi-source parallel BFS traversal with deduplication */ traverseParallel(collection: string, request: TraverseParallelRequest): Promise; /** Get the in-degree and out-degree of a node */ getNodeDegree(collection: string, nodeId: number): Promise; /** * Search a named sparse index (issue #380). * * Sends `sparse_vectors: { [indexName]: query }` and `sparse_index: indexName` * to the `/search` endpoint. When `options.vector` is provided, the request * also includes a dense vector for hybrid sparse+dense search against the * named index. * * WASM backend: not supported (throws `VelesDB-WASM-NOT-SUPPORTED`). */ sparseSearchNamed(collection: string, query: SparseVector, indexName: string, options?: SparseSearchNamedOptions): Promise; /** Train Product Quantization on a collection */ trainPq(collection: string, options?: PqTrainOptions): Promise; /** * Enable the bounded streaming-ingestion channel on a collection. * * POSTs an optional `StreamingConfig` to * `POST /collections/{name}/stream/enable`; omitted config fields fall * back to the server defaults. Must be called before `streamInsert`. */ enableStreaming(collection: string, config?: StreamingConfig): Promise; /** Stream-insert documents with backpressure support */ streamInsert(collection: string, docs: VectorDocument[]): Promise; /** * Batch upsert points via the NDJSON streaming endpoint. * * Sends all documents as a single NDJSON request to * `POST /collections/{name}/points/stream` (up to 100 MB). * Returns server-side processing statistics. */ streamUpsertPoints(collection: string, docs: VectorDocument[]): Promise; /** Create a graph collection */ createGraphCollection(name: string, config?: GraphCollectionConfig): Promise; /** Get collection statistics */ getCollectionStats(collection: string): Promise; /** Analyze a collection */ analyzeCollection(collection: string): Promise; /** Get collection configuration */ getCollectionConfig(collection: string): Promise; /** Search returning only IDs and scores */ searchIds(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise>; /** Store a semantic fact */ storeSemanticFact(collection: string, entry: SemanticEntry): Promise; /** Search semantic memory */ searchSemanticMemory(collection: string, embedding: number[], k?: number): Promise; /** * Record an episodic event. Returns the point ID as a string (u64 * precision preserved). */ recordEpisodicEvent(collection: string, event: EpisodicEvent): Promise; /** Recall episodic events by vector similarity. */ recallEpisodicEvents(collection: string, embedding: number[], k?: number): Promise; /** * Recall episodic events most-recent-first, optionally bounded below by * `since` (inclusive unix-seconds). Mirrors core `episodic.recent(since)`. */ recallRecentEvents(collection: string, since?: number): Promise; /** * Recall episodic events strictly older than `before` (unix-seconds), * most-recent-first. Mirrors core `episodic.older_than(before)`. */ recallOlderThanEvents(collection: string, before: number): Promise; /** * Store a procedural pattern. Returns the point ID as a string (u64 * precision preserved). */ storeProceduralPattern(collection: string, pattern: ProceduralPattern): Promise; /** Match procedural patterns */ matchProceduralPatterns(collection: string, embedding: number[], k?: number): Promise; /** Rebuild a collection's HNSW index (compacts tombstones). */ rebuildIndex(collection: string): Promise; /** Read the current process-wide guard-rails configuration. */ getGuardrails(): Promise; /** Partial-update the process-wide guard-rails configuration. */ updateGuardrails(req: GuardRailsUpdateRequest): Promise; /** Execute a VelesQL aggregate query (COUNT/AVG/GROUP BY/...). */ aggregate(queryString: string, params?: Record, options?: AggregateQueryOptions): Promise; /** Execute a VelesQL `MATCH (...)` graph query scoped to a collection. */ matchQuery(collection: string, queryString: string, params?: Record, options?: MatchQueryOptions): Promise; /** Remove a graph edge by ID. Returns `true` if removed, `false` if not found. */ removeEdge(collection: string, edgeId: number): Promise; /** Total edge count in a graph collection. */ getEdgeCount(collection: string): Promise; /** List every node ID in a graph collection. */ listNodes(collection: string): Promise; /** Get edges adjacent to a node (filterable by direction + label). */ getNodeEdges(collection: string, nodeId: number, options?: GetNodeEdgesOptions): Promise; /** Read the JSON payload attached to a graph node. */ getNodePayload(collection: string, nodeId: number): Promise; /** Upsert (create or replace) the JSON payload of a graph node. */ upsertNodePayload(collection: string, nodeId: number, payload: Record): Promise; /** Vector similarity search scoped to graph nodes only. */ graphSearch(collection: string, request: GraphSearchRequest): Promise; /** Create a typed relation edge between two points. Returns the allocated edge ID. */ relate(collection: string, req: RelateRequest): Promise; /** Remove a relation edge by ID. Returns `true` if removed. */ unrelate(collection: string, edgeId: GraphNodeId): Promise; /** List outgoing relation edges for a point. */ getRelations(collection: string, pointId: GraphNodeId): Promise; /** Durably set (or refresh) the TTL of a point. */ setTtlDurable(collection: string, pointId: GraphNodeId, ttlSeconds: number): Promise; } /** * VelesDB TypeScript SDK - Error Type Definitions * * SDK-level error classes for transport and validation errors. * @packageDocumentation */ /** Error types */ declare class VelesDBError extends Error { readonly code: string; readonly cause?: Error | undefined; constructor(message: string, code: string, cause?: Error | undefined); } declare class ConnectionError extends VelesDBError { constructor(message: string, cause?: Error); } declare class ValidationError extends VelesDBError { constructor(message: string); } declare class NotFoundError extends VelesDBError { constructor(resource: string); } /** Thrown when stream insert receives 429 Too Many Requests (backpressure) */ declare class BackpressureError extends VelesDBError { constructor(message?: string); } /** * Agent Memory facade for VelesDB. * * Provides semantic, episodic, and procedural memory abstractions * on top of the VelesDB backend interface. */ /** * Agent Memory client for semantic, episodic, and procedural memory */ declare class AgentMemoryClient { private readonly backend; private readonly config?; constructor(backend: IVelesDBBackend, config?: AgentMemoryConfig | undefined); /** * Advisory embedding dimension passed at construction (default: 384). * * This value is **not** enforced and does not create or size any * collection — the dimension that actually governs storage and search * is the one fixed when the collection was created * (`db.createCollection(name, { dimension, metric: 'cosine' })`). * Embeddings you pass to `storeFact` / `recordEvent` / `learnProcedure` * must match that collection dimension. */ get dimension(): number; /** Store a semantic fact */ storeFact(collection: string, entry: SemanticEntry): Promise; /** Search semantic memory */ searchFacts(collection: string, embedding: number[], k?: number): Promise; /** Record an episodic event. Returns the point ID (string, u64-safe). */ recordEvent(collection: string, event: EpisodicEvent): Promise; /** Recall episodic events by vector similarity. */ recallEvents(collection: string, embedding: number[], k?: number): Promise; /** * Recall episodic events most-recent-first, optionally bounded below by * `since` (inclusive unix-seconds). Mirrors core `episodic.recent(since)`. */ recallRecent(collection: string, since?: number): Promise; /** * Recall episodic events strictly older than `before` (unix-seconds), * most-recent-first. Mirrors core `episodic.older_than(before)`. */ recallOlderThan(collection: string, before: number): Promise; /** Store a procedural pattern. Returns the point ID (string, u64-safe). */ learnProcedure(collection: string, pattern: ProceduralPattern): Promise; /** Match procedural patterns */ recallProcedures(collection: string, embedding: number[], k?: number): Promise; /** * Delete a memory entry (fact, event, or procedure) by its point ID. * * Accepts the `string` ids returned by `recordEvent` / `learnProcedure` * (u64-safe decimal strings) as well as numeric ids. */ deleteMemory(collection: string, id: string | number): Promise; } /** * VelesDB Client - Unified interface for all backends */ /** * VelesDB Client * * Provides a unified interface for interacting with VelesDB * using either WASM (browser/Node.js) or REST API backends. */ declare class VelesDB { private readonly config; private backend; private initialized; constructor(config: VelesDBConfig); private validateConfig; private createBackend; /** Initialize the client. Must be called before any other operations. */ init(): Promise; /** Check if client is initialized. */ isInitialized(): boolean; private ensureInitialized; createCollection(name: string, config: CollectionConfig): Promise; createMetadataCollection(name: string): Promise; deleteCollection(name: string): Promise; getCollection(name: string): Promise; listCollections(): Promise; upsert(collection: string, doc: VectorDocument): Promise; upsertBatch(collection: string, docs: VectorDocument[]): Promise; /** * Bulk upsert via the binary wire format (REST backend only). * * Encodes `(id, vector)` pairs into the deterministic VRB1 binary layout * and sends them as a single `application/octet-stream` request, avoiding * per-point JSON overhead. Payloads are not carried — use * {@link upsertBatch} when you need them. Throws a not-supported error on * the WASM backend. * * @returns the number of points the server reports as inserted. */ upsertBatchRaw(collection: string, docs: VectorDocument[]): Promise; delete(collection: string, id: string | number): Promise; bulkDelete(collection: string, ids: Array): Promise; get(collection: string, id: string | number): Promise; isEmpty(collection: string): Promise; flush(collection: string): Promise; close(): Promise; search(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise; searchBatch(collection: string, searches: Array<{ vector: number[] | Float32Array; k?: number; filter?: FilterInput; quality?: SearchQuality; }>): Promise; textSearch(collection: string, query: string, options?: { k?: number; filter?: FilterInput; }): Promise; hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: { k?: number; vectorWeight?: number; filter?: FilterInput; }): Promise; multiQuerySearch(collection: string, vectors: Array, options?: MultiQuerySearchOptions): Promise; /** Multi-query fusion search returning only IDs and scores (no payloads). */ multiQuerySearchIds(collection: string, vectors: Array, options?: MultiQuerySearchOptions): Promise>; /** * Pure sparse search against a named sparse index. * * @see {@link SparseSearchNamedOptions} for the full pure-sparse vs hybrid comparison. * @see {@link VelesDB.search} for dense + sparse hybrid against a named index. */ sparseSearchNamed(collection: string, query: SparseVector, indexName: string, options?: SparseSearchNamedOptions): Promise; query(collection: string, queryString: string, params?: Record, options?: QueryOptions): Promise; queryExplain(queryString: string, params?: Record, options?: { analyze?: boolean; }): Promise; collectionSanity(collection: string): Promise; scroll(collection: string, request?: ScrollRequest): Promise; trainPq(collection: string, options?: PqTrainOptions): Promise; enableStreaming(collection: string, config?: StreamingConfig): Promise; streamInsert(collection: string, docs: VectorDocument[]): Promise; streamUpsertPoints(collection: string, docs: VectorDocument[]): Promise; searchIds(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise>; rebuildIndex(collection: string): Promise; getGuardrails(): Promise; updateGuardrails(req: GuardRailsUpdateRequest): Promise; aggregate(queryString: string, params?: Record, options?: AggregateQueryOptions): Promise; getCollectionStats(collection: string): Promise; analyzeCollection(collection: string): Promise; getCollectionConfig(collection: string): Promise; createIndex(collection: string, options: CreateIndexOptions): Promise; listIndexes(collection: string): Promise; hasIndex(collection: string, label: string, property: string): Promise; dropIndex(collection: string, label: string, property: string): Promise; /** * Toggle a collection's mutable settings at runtime via * `ALTER COLLECTION SET(...)`. * * Typed wrapper over the raw VelesQL DDL; routes through the same * `/query` path as `db.query()`. * * @example * ```typescript * await db.alterCollection('docs', { autoReindex: true }); * ``` */ alterCollection(collection: string, options: AlterCollectionOptions): Promise; /** * Enable or disable automatic index rebuilds on a collection. * * Convenience wrapper over {@link alterCollection}; emits * `ALTER COLLECTION SET(auto_reindex=)`. */ setAutoReindex(collection: string, enabled: boolean): Promise; addEdge(collection: string, edge: AddEdgeRequest): Promise; getEdges(collection: string, options?: GetEdgesOptions): Promise; traverseGraph(collection: string, request: TraverseRequest): Promise; traverseParallel(collection: string, request: TraverseParallelRequest): Promise; getNodeDegree(collection: string, nodeId: number): Promise; createGraphCollection(name: string, config?: GraphCollectionConfig): Promise; matchQuery(collection: string, queryString: string, params?: Record, options?: MatchQueryOptions): Promise; removeEdge(collection: string, edgeId: number): Promise; getEdgeCount(collection: string): Promise; listNodes(collection: string): Promise; getNodeEdges(collection: string, nodeId: number, options?: GetNodeEdgesOptions): Promise; getNodePayload(collection: string, nodeId: number): Promise; upsertNodePayload(collection: string, nodeId: number, payload: Record): Promise; graphSearch(collection: string, request: GraphSearchRequest): Promise; relate(collection: string, req: RelateRequest): Promise; unrelate(collection: string, edgeId: GraphNodeId): Promise; getRelations(collection: string, pointId: GraphNodeId): Promise; setTtlDurable(collection: string, pointId: GraphNodeId, ttlSeconds: number): Promise; capabilities(): Readonly; get backendType(): string; agentMemory(config?: AgentMemoryConfig): AgentMemoryClient; } /** * WASM Backend * * Provides vector storage using WebAssembly for optimal performance * in browser and Node.js environments. */ declare class WasmBackend implements IVelesDBBackend { private wasmModule; private collections; private _initialized; private _initInFlight; private _initGen; init(): Promise; private runInit; isInitialized(): boolean; close(): Promise; capabilities(): Readonly; private ensureInitialized; createCollection(name: string, config: CollectionConfig): Promise; deleteCollection(name: string): Promise; getCollection(name: string): Promise; listCollections(): Promise; upsert(collectionName: string, doc: VectorDocument): Promise; upsertBatch(collectionName: string, docs: VectorDocument[]): Promise; upsertBatchRaw(c: string, d: VectorDocument[]): Promise; delete(collectionName: string, id: string | number): Promise; bulkDelete(collectionName: string, ids: Array): Promise; get(collectionName: string, id: string | number): Promise; isEmpty(collectionName: string): Promise; flush(collectionName: string): Promise; search(c: string, q: number[] | Float32Array, o?: SearchOptions): Promise; searchBatch(c: string, s: Array<{ vector: number[] | Float32Array; k?: number; filter?: FilterInput; quality?: SearchQuality; }>): Promise; textSearch(c: string, q: string, o?: { k?: number; filter?: FilterInput; }): Promise; hybridSearch(c: string, v: number[] | Float32Array, t: string, o?: { k?: number; vectorWeight?: number; filter?: FilterInput; }): Promise; query(c: string, q: string, p?: Record, o?: QueryOptions): Promise; multiQuerySearch(c: string, v: Array, o?: MultiQuerySearchOptions): Promise; queryExplain(q: string, p?: Record, o?: { analyze?: boolean; }): Promise; collectionSanity(c: string): Promise; scroll(c: string, r?: ScrollRequest): Promise; createIndex(c: string, o: CreateIndexOptions): Promise; listIndexes(c: string): Promise; hasIndex(c: string, l: string, p: string): Promise; dropIndex(c: string, l: string, p: string): Promise; addEdge(c: string, e: AddEdgeRequest): Promise; getEdges(c: string, o?: GetEdgesOptions): Promise; traverseGraph(c: string, r: TraverseRequest): Promise; traverseParallel(c: string, r: TraverseParallelRequest): Promise; getNodeDegree(c: string, n: number): Promise; trainPq(c: string, o?: PqTrainOptions): Promise; enableStreaming(c: string, cfg?: StreamingConfig): Promise; streamInsert(c: string, d: VectorDocument[]): Promise; streamUpsertPoints(c: string, d: VectorDocument[]): Promise; createGraphCollection(n: string, c?: GraphCollectionConfig): Promise; getCollectionStats(c: string): Promise; analyzeCollection(c: string): Promise; getCollectionConfig(c: string): Promise; searchIds(c: string, q: number[] | Float32Array, o?: SearchOptions): Promise>; multiQuerySearchIds(c: string, v: Array, o?: MultiQuerySearchOptions): Promise>; storeSemanticFact(c: string, e: SemanticEntry): Promise; searchSemanticMemory(c: string, e: number[], k?: number): Promise; recordEpisodicEvent(c: string, e: EpisodicEvent): Promise; recallEpisodicEvents(c: string, e: number[], k?: number): Promise; recallRecentEvents(c: string, since?: number): Promise; recallOlderThanEvents(c: string, before: number): Promise; storeProceduralPattern(c: string, p: ProceduralPattern): Promise; matchProceduralPatterns(c: string, e: number[], k?: number): Promise; rebuildIndex(c: string): Promise; getGuardrails(): Promise; updateGuardrails(r: GuardRailsUpdateRequest): Promise; aggregate(_q: string, _p?: Record, _o?: AggregateQueryOptions): Promise; matchQuery(c: string, q: string, p?: Record, o?: MatchQueryOptions): Promise; removeEdge(c: string, id: number): Promise; getEdgeCount(c: string): Promise; listNodes(c: string): Promise; getNodeEdges(c: string, id: number, o?: GetNodeEdgesOptions): Promise; getNodePayload(c: string, id: number): Promise; upsertNodePayload(c: string, id: number, p: Record): Promise; graphSearch(c: string, r: GraphSearchRequest): Promise; sparseSearchNamed(c: string, q: SparseVector, idx: string, o?: SparseSearchNamedOptions): Promise; relate(c: string, req: RelateRequest): Promise; unrelate(c: string, edgeId: GraphNodeId): Promise; getRelations(c: string, pointId: GraphNodeId): Promise; setTtlDurable(c: string, pointId: GraphNodeId, ttlSeconds: number): Promise; } /** * REST Backend * * Provides vector storage via VelesDB REST API server. */ declare class RestBackend implements IVelesDBBackend { private readonly httpConfig; private _initialized; constructor(url: string, apiKey?: string, timeout?: number); init(): Promise; isInitialized(): boolean; capabilities(): Readonly; close(): Promise; private ensureInitialized; createCollection(n: string, c: CollectionConfig): Promise; deleteCollection(n: string): Promise; getCollection(n: string): Promise; listCollections(): Promise; upsert(c: string, d: VectorDocument): Promise; upsertBatch(c: string, d: VectorDocument[]): Promise; upsertBatchRaw(c: string, d: VectorDocument[]): Promise; delete(c: string, id: string | number): Promise; bulkDelete(c: string, ids: Array): Promise; get(c: string, id: string | number): Promise; isEmpty(c: string): Promise; flush(c: string): Promise; rebuildIndex(c: string): Promise; getGuardrails(): Promise; updateGuardrails(r: GuardRailsUpdateRequest): Promise; aggregate(q: string, p?: Record, o?: AggregateQueryOptions): Promise; matchQuery(c: string, q: string, p?: Record, o?: MatchQueryOptions): Promise; removeEdge(c: string, id: number): Promise; getEdgeCount(c: string): Promise; listNodes(c: string): Promise; getNodeEdges(c: string, id: number, o?: GetNodeEdgesOptions): Promise; getNodePayload(c: string, id: number): Promise; upsertNodePayload(c: string, id: number, p: Record): Promise; graphSearch(c: string, r: GraphSearchRequest): Promise; relate(c: string, req: RelateRequest): Promise; unrelate(c: string, edgeId: GraphNodeId): Promise; getRelations(c: string, pointId: GraphNodeId): Promise; setTtlDurable(c: string, pointId: GraphNodeId, ttlSeconds: number): Promise; search(c: string, q: number[] | Float32Array, o?: SearchOptions): Promise; searchBatch(c: string, s: Array<{ vector: number[] | Float32Array; k?: number; filter?: FilterInput; quality?: SearchQuality; }>): Promise; textSearch(c: string, q: string, o?: { k?: number; filter?: FilterInput; }): Promise; hybridSearch(c: string, v: number[] | Float32Array, t: string, o?: { k?: number; vectorWeight?: number; filter?: FilterInput; }): Promise; multiQuerySearch(c: string, v: Array, o?: MultiQuerySearchOptions): Promise; multiQuerySearchIds(c: string, v: Array, o?: MultiQuerySearchOptions): Promise>; searchIds(c: string, q: number[] | Float32Array, o?: SearchOptions): Promise>; sparseSearchNamed(c: string, q: SparseVector, idx: string, o?: SparseSearchNamedOptions): Promise; query(c: string, q: string, p?: Record, o?: QueryOptions): Promise; queryExplain(q: string, p?: Record, o?: { analyze?: boolean; }): Promise; collectionSanity(c: string): Promise; scroll(c: string, r?: ScrollRequest): Promise; addEdge(c: string, e: AddEdgeRequest): Promise; getEdges(c: string, o?: GetEdgesOptions): Promise; traverseGraph(c: string, r: TraverseRequest): Promise; traverseParallel(c: string, r: TraverseParallelRequest): Promise; getNodeDegree(c: string, id: number): Promise; createGraphCollection(n: string, c?: GraphCollectionConfig): Promise; createIndex(c: string, o: CreateIndexOptions): Promise; listIndexes(c: string): Promise; hasIndex(c: string, l: string, p: string): Promise; dropIndex(c: string, l: string, p: string): Promise; getCollectionStats(c: string): Promise; analyzeCollection(c: string): Promise; getCollectionConfig(c: string): Promise; trainPq(c: string, o?: PqTrainOptions): Promise; enableStreaming(c: string, cfg?: StreamingConfig): Promise; streamInsert(c: string, d: VectorDocument[]): Promise; streamUpsertPoints(c: string, d: VectorDocument[]): Promise; storeSemanticFact(c: string, e: SemanticEntry): Promise; searchSemanticMemory(c: string, e: number[], k?: number): Promise; recordEpisodicEvent(c: string, e: EpisodicEvent): Promise; recallEpisodicEvents(c: string, e: number[], k?: number): Promise; recallRecentEvents(c: string, since?: number): Promise; recallOlderThanEvents(c: string, before: number): Promise; storeProceduralPattern(c: string, p: ProceduralPattern): Promise; matchProceduralPatterns(c: string, e: number[], k?: number): Promise; } /** * VelesDB Memory Wedge — local-first agent memory (WASM-backed). * * A standalone client, not a facade over {@link IVelesDBBackend}: the wedge * is a single in-memory store (no `collection` parameter, no REST * counterpart), architecturally distinct from the collection-scoped vector * API the rest of the SDK wraps. Mirrors the Node (`@wiscale/velesdb-memory-node`) * and Python bindings' own standalone `MemoryService` class rather than * bolting onto the generic backend interface — which also sidesteps a real * naming collision (`IVelesDBBackend.relate` is the graph-edge API, a * different shape than the memory wedge's `relate(from, to, relation)`). * * @packageDocumentation */ /** A typed link to an existing memory (input to {@link MemoryService.remember}). */ interface MemoryLink { /** Decimal-string id of the memory being linked to. */ target: string; /** Relationship label, e.g. `"decided_in"`. */ relation: string; } /** * Metadata shape every `remember`-d fact carries, extended by whatever * caller-supplied fields were passed. `_veles_date` is a RESERVED key: * `remember` auto-stamps it with today's date (a `YYYYMMDD` integer, e.g. * `20260723`) unless the caller already set it — see `velesdb-memory`'s * README "Automatic dating (`_veles_date`)" section, and this SDK's own * README. Pass `"_veles_date"` as {@link MemoryService.recallFusedDated}'s * `dateField` to get a chronological `datedContext` timeline with zero * setup; set `_veles_date` explicitly in `remember`'s `metadata` only to * override the auto-stamp (e.g. dating a fact by when it actually * happened, not when it was stored). */ interface MemoryMetadata extends Record { /** `YYYYMMDD` integer (e.g. `20260723`) — auto-stamped by `remember` unless already set. */ _veles_date?: number; } /** One recalled memory (output of `recall` / `recallWhere` / `recallFused`). */ interface MemoryRecollection { /** Decimal-string id of the memory. */ id: string; /** Similarity score (higher is closer). */ score: number; /** Stored fact content. */ content: string; /** Caller-supplied structured metadata, or `undefined` when the fact carries none. */ metadata?: MemoryMetadata; } /** * An inline media payload on a {@link CompileContextFragment} (US-009). * `content` on the fragment stays the caption — often empty for a bare * screenshot — while the pixels live here, base64-encoded. The fragment * packs atomically (never chunked) and its token cost comes from the * image itself (dimensions sniffed from the PNG/JPEG header), not its * base64 text. */ interface CompileContextMedia { /** Declared MIME type, e.g. `"image/png"` or `"image/jpeg"`. */ mime: string; /** The raw media bytes, base64-encoded (standard alphabet, padded). */ bytes_b64: string; } /** One input fragment of {@link MemoryService.compileContext}. */ interface CompileContextFragment { /** Optional caller id as a decimal string (content-derived when absent). */ id?: string; /** The fragment text (the caption, when {@link media} is set). */ content: string; /** Classification hint (`"code"`, `"log"`, `"screenshot"`, …). */ kind?: string; /** * Caller priority; higher packs first. Defaults to `0`. * * The knob that decides what survives a tight budget: relevance ordering * anchors on the query, and this overrides it for fragments the caller * already knows must be kept ahead of the rest. * * The wire has accepted it since the compiler shipped; this SDK simply never * declared it, so a TypeScript caller could reach `compileContext` and not * express the one input that controls what it drops. */ priority?: number; /** Fragment flags, e.g. `{ verbatim: true }` or `{ cache: true }`. */ metadata?: Record; /** * Inline media payload (US-009). `undefined` keeps every pre-existing * request wire-compatible. Fetch it back later — inline or externalized * by budget, it makes no difference — through * {@link MemoryService.retrieveContextSource} over the resulting * `ctx://source/` handle. */ media?: CompileContextMedia; } /** * Input of {@link MemoryService.compileContext} — the MCP `compile_context` * wire shape (snake_case keys, ids as decimal strings). */ interface CompileContextRequest { /** The current task — relevance ordering anchors on it. */ query: string; /** Hard budget for the compiled context, in estimated tokens. */ token_budget: number; /** The fragments to compile. */ fragments: CompileContextFragment[]; /** Pull stored memories into the compile (tri-engine recall). */ memory_scope?: Record; /** Compile policy overrides (importance weights, pricing, …). */ policy?: Record; /** Project facet for savings aggregation. */ project?: string; [key: string]: unknown; } /** * Output of {@link MemoryService.compileContext} — the MCP wire shape * (snake_case keys; every id field is a decimal string). */ interface CompiledContext { /** The assembled context, ready to inject into a prompt. */ content: string; /** Ordered output blocks (cache prefix first). */ sections: unknown; /** One auditable decision per input fragment. */ decisions: unknown; /** One source pointer per distinct fragment. */ sources: unknown; /** Handles of externalized fragments (`ctx://source/…`). */ retrieval_handles: unknown; /** Token/cost savings of this compilation. */ insights: unknown; /** Overall fidelity risk. */ risk: 'low' | 'medium' | 'high'; /** Low-noise pointers to relevant fragments that were externalized; inspect `decisions` for the exhaustive audit. */ warnings: unknown; [key: string]: unknown; } /** * Input of {@link MemoryService.compileTranscript} — the same fields as the * MCP `compile_transcript` tool's request MINUS `path`: the wedge runs * entirely in-memory with no filesystem, so only an inline `transcript` is * accepted (there is nothing for a `path` to resolve against). */ interface CompileTranscriptRequest { /** What the agent is working on — drives relevance scoring, like {@link CompileContextRequest.query}. */ query: string; /** * The raw transcript text: plain (marker-based — * `System:`/`User:`/`Human:`/`Assistant:`/`AI:`/`Tool:`/`### User`/`### Assistant`) * or JSONL (one `{role, content}` object per line). */ transcript: string; /** Hard budget for the compiled context, in estimated tokens. */ token_budget: number; /** Project facet for savings aggregation. */ project?: string; /** Target model name, for cost insights. */ target_model?: string; /** Compile policy overrides (importance weights, pricing, …). */ policy?: Record; /** * Tuning knobs for the segmentation step itself (format, merge threshold, * system-turn caching) — omitted uses the engine's documented defaults * (auto-detect format, 256-byte merge threshold, cache the system turn). */ segmentation?: { /** Force `"plain"` or `"jsonl"` instead of auto-detecting. */ format?: 'auto' | 'plain' | 'jsonl'; /** Segments under this many bytes merge into an adjacent same-kind segment. */ min_segment_bytes?: number; /** Tag the first turn cache-eligible when it looks like a system prompt. */ cache_system_turn?: boolean; }; [key: string]: unknown; } /** One entry of {@link TranscriptSegmentationReport.segments} — the audit trail of how a transcript was cut. */ interface TranscriptSegmentInfo { /** Position of this segment in the segmentation, in transcript order. */ index: number; /** Which turn (0-based) this segment belongs to. */ turn: number; /** The turn's role, when one was determined; absent for a `plain` transcript with no matching marker. */ role?: string; /** `"body"`, `"code"`, or `"log"`. */ kind: 'body' | 'code' | 'log'; /** Start byte offset (inclusive) in the original transcript. */ byte_start: number; /** End byte offset (exclusive) in the original transcript. */ byte_end: number; /** The decimal-string id this segment's fragment carries into `context.decisions`. */ fragment_id: string; } /** How {@link MemoryService.compileTranscript} cut the transcript into fragments before compiling. */ interface TranscriptSegmentationReport { /** `"plain"` or `"jsonl"` — the format actually used, never `"auto"` even when requested. */ format_detected: 'plain' | 'jsonl'; /** Every segment, in transcript order. */ segments: TranscriptSegmentInfo[]; /** How many segments the merge step eliminated. */ merged_segments: number; } /** Output of {@link MemoryService.compileTranscript}. */ interface CompileTranscriptResult { /** The compiled context — byte-compatible with {@link MemoryService.compileContext}'s own output. */ context: CompiledContext; /** How the transcript was cut into fragments before compilation. */ segmentation: TranscriptSegmentationReport; } /** * One decision of a {@link MemoryService.compileContext} / * {@link MemoryService.compileTranscript} request, as returned by * {@link MemoryService.explainCompilation}: why one fragment was preserved, * abstracted, externalized, dropped, or cached. */ interface ContextDecision { /** The fragment this decision is about (decimal-string id). */ fragment_id: string; /** Content hash of the original fragment text (decimal-string id). */ content_hash: string; /** What was done: `"preserve"`, `"abstract"`, `"externalize"`, `"drop"`, or `"cache"`. */ action: string; /** The stable id of the rule that decided (e.g. `"preserve.code_fence"`). */ rule_id: string; /** Lexical relevance of the fragment to the request query, in `[0, 1]`. */ relevance: number; /** Fidelity risk this single decision contributes. */ risk: 'low' | 'medium' | 'high'; /** Human-readable explanation of the decision. */ reason: string; /** The backing memory's decimal-string id, present only for a memory-scope-pulled fragment. */ memory_id?: string; /** A `ctx://source/` retrieval handle, present only for an externalized/partially-packed fragment. */ handle?: string; [key: string]: unknown; } /** * Output of {@link MemoryService.contextSavings}: aggregated token (and * cost) savings of past {@link MemoryService.compileContext} / * {@link MemoryService.compileTranscript} calls. */ interface ContextSavings { /** Number of compilation events aggregated. */ events: number; /** Sum of estimated input tokens across events. */ tokens_in: number; /** Sum of estimated output tokens across events. */ tokens_out: number; /** Sum of estimated tokens saved across events. */ tokens_saved: number; /** Estimated cost avoided, in micro-units, keyed by currency. */ cost_saved_micros_by_currency: Record; /** `true` when the aggregation hit the recall cap — older events beyond it were not folded in. */ truncated: boolean; [key: string]: unknown; } /** Output of {@link MemoryService.suggestBudget}. */ interface SuggestedBudget { /** The model's context window, in tokens — `null` when the model is not in the static table. */ window: number | null; /** `window - reserveTokens` (saturating at 0) — `null` when `window` is `null`. */ suggested_budget: number | null; /** Provenance of the static table, dated — never "measured" or "fetched". */ source: string; } /** * Output of {@link MemoryService.retrieveContextSource} — the exact original * content (and media, when the fragment carried one) behind a * `ctx://source/` handle from a {@link MemoryService.compileContext} * result. Same wire shape as the Node binding's own `retrieveContextSource`. */ interface ContextSource { /** The handle this source was resolved from (echoed back). */ handle: string; /** The exact original fragment text. */ content: string; /** Present only when the fragment carried an inline media payload. */ media?: CompileContextMedia; [key: string]: unknown; } /** * The distilled working state of an agent session, persisted and reloaded * via {@link MemoryService.saveWorkingContext} / * {@link MemoryService.loadWorkingContext} (#1517). Same wire shape as the * Node binding's `WorkingContext` (snake_case keys); nested fact/decision * shapes are kept as `unknown` here, matching {@link CompiledContext}'s own * convention for wire-shaped sub-objects this SDK does not otherwise need * to inspect. */ interface WorkingContext { /** What the session is trying to achieve. */ goal?: string; /** Constraints currently in force (never compressed away). */ active_constraints?: unknown[]; /** Facts that were verified, with their sources. */ verified_facts?: unknown[]; /** Hypotheses still open. */ open_hypotheses?: unknown[]; /** Decisions taken so far (`{fragment_id, rule_id}`, `fragment_id` a decimal string). */ decisions?: unknown[]; /** Exact evidence the session relies on (verbatim, addressable). */ exact_evidence?: unknown[]; /** Actions still to do. */ pending_actions?: string[]; [key: string]: unknown; } /** One session recorded in a project's working-context index (output of {@link MemoryService.listWorkingContexts}). */ interface WorkingContextSession { /** The session id, as passed to {@link MemoryService.saveWorkingContext}. */ session: string; /** Unix seconds this session was last saved. */ saved_at: number; } /** * What {@link MemoryService.loadWorkingContext} resolves to — the same * three-field envelope the MCP `load_working_context` tool serves. * * **BREAKING (`velesdb-memory` 0.12.0, relayed by the next * `@wiscale/velesdb-sdk` release)**: `loadWorkingContext` used to resolve * `WorkingContext | null`. That bare form collapsed two different answers * into one — a project that never saved anything, and a typo in `session` * that missed a session which does exist. Read {@link working} for the * previous return value. * * The version named is the memory crate's. This package is on the 4.x line * and will never have a 0.12.0, so "breaking in 0.12.0" unqualified would * read to anyone pinned at 4.x as a change already behind them. */ interface LoadedWorkingContext { /** `true` when a working context was found under this exact project + session. */ found: boolean; /** * The previously saved working context, or `null` when nothing was ever * saved under that project + session (a fresh start, not an error). */ working: WorkingContext | null; /** * The OTHER sessions saved under this SAME project — never the requested * one. Filled in on a HIT as well as on a miss: a typo that lands on * another real session is the case a caller can least detect on its own. * Empty only when the project has no other session. */ other_sessions: string[]; } /** Result of {@link MemoryService.listWorkingContexts}. */ interface ListWorkingContextsResult { /** Every session saved under this project, most-recently-saved first. */ sessions: WorkingContextSession[]; } /** A structured predicate for {@link MemoryService.recallWhere}. */ interface MemoryColumnFilter { /** Metadata field name (alphanumeric/underscore). */ field: string; /** Comparison operator. */ op: 'eq' | 'ne' | 'lt' | 'le' | 'gt' | 'ge'; /** Value to compare against (string, number, or boolean). */ value: string | number | boolean; } /** * Tuning knobs for {@link MemoryService.recallFused}. Every field is * optional; an omitted field falls back to the proven default (`hops: 2`, * `graphBoost: 0.15`, an oversampled pool). */ interface MemoryFusionOptions { /** Hops the graph traversal walks from the top vector seed. */ hops?: number; /** Weight added to a graph-reached fact's normalised vector score. */ graphBoost?: number; /** Depth of the oversampled vector pool fusion re-ranks. */ pool?: number; } /** Result of {@link MemoryService.recallFusedDated}: the recalled memories plus a dated timeline. */ interface MemoryDatedRecall { /** Recalled memories, most relevant first. */ memories: MemoryRecollection[]; /** * Chronological, date-prefixed rendering of {@link memories} * (`- [YYYY-MM-DD] content` per line, oldest first, undated facts last). */ datedContext: string; /** The most recent date across {@link memories} (`YYYY-MM-DD`), or `null` when none is dated. */ now: string | null; } /** A node in a {@link MemoryService.why} explanation subgraph. */ interface MemoryNode { /** Decimal-string id of the memory. */ id: string; /** Stored fact content. */ content: string; /** Distance in hops from the seed (seed is `0`). */ hop: number; } /** A typed edge in a {@link MemoryService.why} explanation subgraph. */ interface MemoryEdge { /** Source memory id (decimal string). */ from: string; /** Target memory id (decimal string). */ to: string; /** Relationship label. */ relation: string; } /** The connected answer to a {@link MemoryService.why} question. */ interface MemoryExplanation { /** Memories in the subgraph, seed first. */ nodes: MemoryNode[]; /** Typed edges connecting the nodes. */ edges: MemoryEdge[]; /** * `true` when a width budget cut the walk before it exhausted the reachable * graph. Counts alone cannot say it: a subgraph sitting exactly at a cap is * indistinguishable from a complete one. */ truncated: boolean; } /** What {@link MemoryService.unrelate} actually removed. */ interface MemoryUnrelateOutcome { /** Whether at least one matching edge existed and was removed. */ found: boolean; /** How many matching edges were removed (parallel duplicates included). */ removed: number; } /** * One typed edge touching an entity. Which end `targetId`/`target` name * depends on the list it came from: in {@link MemoryEntityProfile.relations} * it is the far end the edge points AT, in * {@link MemoryEntityProfile.relationsIn} the far end it comes FROM. */ interface MemoryEntityRelation { /** The edge label the passage stated, e.g. `"sister of"`. */ predicate: string; /** Decimal-string id of the entity (or fact) on the far end. */ targetId: string; /** Stored content of the far end — for an entity hub, `Entity: `. */ target: string; } /** Everything the auto-built graph knows about one named entity. */ interface MemoryEntityProfile { /** Whether an entity is known under that name at all. */ found: boolean; /** Decimal-string, content-addressed id of the entity (`"0"` on a miss). */ id: string; /** Canonical (trimmed, lowercased) entity name — filled in hit or miss. */ name: string; /** Attributes learned about this entity, reserved keys stripped. */ attributes: Record; /** Typed edges LEAVING this entity. */ relations: MemoryEntityRelation[]; /** * Typed edges pointing AT this entity. Without them a question is only * answerable from one side: the graph holds `camille --sister of--> theo`, * so reading Theo's outgoing edges never finds Camille. */ relationsIn: MemoryEntityRelation[]; /** * `true` when {@link MemoryEntityProfile.relations} is a PARTIAL view — a * response budget cut the outgoing side. A list holding exactly the cap is * otherwise indistinguishable from a cut one. */ relationsTruncated: boolean; /** `true` when {@link MemoryEntityProfile.relationsIn} is a partial view. */ relationsInTruncated: boolean; } /** Outcome of {@link MemoryService.rememberExtracted}. */ interface RememberedExtraction { /** Decimal-string ids of the stored facts, in extraction order. */ ids: string[]; /** * How many extracted facts were dropped for exceeding the embeddable cap. * Without it a shorter `ids` cannot say why it is short — a silence about * lost data, not a missing convenience. */ skippedOverCap: number; } /** * Local-first agent memory: remember facts, recall them semantically, * relate them, forget them, and ask why a decision was made (a connected * subgraph). Runs entirely in-process (browser or Node) via WebAssembly — * no server, no network. * * One method available on the Node (`@wiscale/velesdb-memory-node`) and * Python bindings is deliberately absent here (issue #1547's audit): * * - `feedback` (RL Memory re-ranking): the underlying * `MemoryService::feedback` lives behind `velesdb-memory`'s * `persistence` feature, which the WASM build does not enable — a * durable learned confidence is meaningless for a store that disappears * on page reload (see `crates/velesdb-wasm/src/memory_service.rs`'s * module doc). Not a missing binding; an intentional boundary. * * `rememberExtracted` (once on that absent list) IS available: it runs the * deterministic `outline` extractor in-process; generative backends are * refused by name so no network dependency enters the WASM bundle. * * @example * ```typescript * const memory = new MemoryService({ dimension: 384 }); * await memory.init(); * const id = await memory.remember('we chose parking_lot to avoid lock poisoning'); * const hits = await memory.recall('lock poisoning'); * ``` */ declare class MemoryService { private readonly dimension; private inner; private _initialized; private _initInFlight; constructor(options?: { dimension?: number; }); /** Load the WASM module and create the underlying in-memory store. */ init(): Promise; private runInit; isInitialized(): boolean; /** Release the underlying WASM store. */ close(): Promise; private ensureInitialized; /** * Runtime capability guard for a `WasmMemoryService` method that shipped * AFTER the class's own base floor (`runInit()`'s `MemoryService` presence * check). A resolved build that has the `MemoryService` class but not this * specific method would otherwise fail with a raw, unhelpful * `TypeError: x is not a function` from deep inside `wrapWasmCall` — this * throws with the same actionable-cause contract `runInit()`'s own * capability check uses, so every version-floor failure in this file reads * the same way regardless of which method hit it. * * `since` is the CALLER's floor rather than a constant in here. It used to * be one message naming a fixed group of four methods and a fixed version, * which was true when written and became false the moment a fifth method * needed a later release. A guard whose explanation drifts away from what * it guards is worse than none — it sends the reader to the wrong version. */ private ensureCapability; /** * Store a fact; resolves to its decimal-string id (idempotent on * identical content). `links` are edges to existing memories; `metadata` * is optional structured data for later filtering; `ttlSeconds` makes the * fact expire after that many seconds. Omit it for a permanent memory, * including when re-storing a fact that already had an expiry — only what * this call supplies is applied. An explicit `0` is REFUSED, because a * caller writing `0` means "expire now", not "never". */ remember(fact: string, options?: { links?: MemoryLink[]; metadata?: MemoryMetadata; ttlSeconds?: number; }): Promise; /** * Recall up to `k` (default 10) memories similar to `query`, optionally * narrowed by an exact-match metadata `filter`. */ recall(query: string, k?: number, filter?: Record): Promise; /** * Fused vector + `ColumnStore` recall: like {@link recall} but `filters` * support ranges/comparisons (`gt`, `le`, …), so temporal/numeric facets * become queryable. * * Returns your own stored facts ONLY: entity hubs and the context compiler's * artefacts (stored sources, compilation events, working contexts and their * index) are internal scaffolding and never come back, whatever the * predicate — including a `ne` one, which matches facts lacking the field * entirely. */ recallWhere(query: string, filters: MemoryColumnFilter[], k?: number): Promise; /** * Fused vector + graph recall: like {@link recall}, but also walks the * graph from the top vector hit and promotes any fact it reaches into the * ranking — the tri-engine ranking measured on HotpotQA/TimeQA/LoCoMo. */ recallFused(query: string, k?: number, filter?: Record, opts?: MemoryFusionOptions): Promise; /** * Fused recall plus a dated timeline: like {@link recallFused}, but reads each * fact's date from the `dateField` metadata key (a `YYYYMMDD` integer) and * resolves to `{ memories, datedContext, now }` — the memories, a chronological * date-prefixed timeline, and a "now" anchor for temporal reasoning. * * Pass `"_veles_date"` as `dateField` for zero-setup dating: {@link remember} * auto-stamps every fact's metadata with {@link MemoryMetadata._veles_date} — * today's date, as a `YYYYMMDD` integer — unless the caller already set it, * so this works without pre-tagging facts yourself. */ recallFusedDated(query: string, dateField: string, k?: number, filter?: Record, opts?: MemoryFusionOptions): Promise; /** Create a typed edge `from -> to`. Resolves to the edge's decimal-string id. */ relate(from: string, to: string, relation: string): Promise; /** * Remove a typed edge between two memories — the inverse of * {@link relate}. Resolves to `{found, removed}`. * * Idempotent by design: an edge that was not there reports * `found: false` rather than throwing, so a cleanup can be replayed. * `removed` counts the edges genuinely deleted, since two facts can carry * several parallel edges under one label. * * Not to be confused with `VelesDBClient.unrelate`, which deletes a GRAPH * edge inside a collection — a different store and a different shape. The * name collision is the same one that kept this class standalone rather * than folded into `IVelesDBBackend`. */ unrelate(from: string, to: string, relation: string): Promise; /** * Look up everything the memory graph knows about a NAMED ENTITY (a * person, a place, an organisation): the attributes merged onto its hub * and the typed edges touching it, in BOTH directions. * * Answers a question ABOUT a thing ("how old is X", "who is X's father") * rather than about the sentences mentioning it, which is all * {@link recall} can return — entity hubs are deliberately invisible to * recall, so without this the attributes {@link rememberExtracted} builds * are unreachable. * * `name` is matched case-insensitively; `found: false` means nothing has * ever mentioned that name, and `name` still echoes the canonicalized * query so several lookups can be told apart. */ entity(name: string): Promise; /** * Extract atomic facts from `text` and store them, auto-building the * entity graph they state. Resolves to `{ids, skippedOverCap}`. * * `extractor` defaults to `"outline"`, the deterministic, network-free * backend: it reads the structure the passage STATES, one directive per * line (`edge: subject | predicate | object`, `attr: entity | key | json`, * `fact: text | topic, topic`). It is the only backend the WASM bundle * carries — a generative one would mean a network call in the bundle this * binding exists to avoid — and any other name is refused rather than * silently substituted. * * This is the WRITE side of {@link entity}: entity hubs are born only of * extraction. */ rememberExtracted(text: string, metadata?: Record, extractor?: string): Promise; /** * Delete a memory by id. Resolves to whether a memory actually existed * under that id and was deleted — `false` means nothing was stored there * (a stale id or a typo), not a second successful deletion. */ forget(id: string): Promise; /** * Explain a decision: the best-matching memory plus its connected * subgraph. `maxHops` (default 2) is capped at 10. */ why(decision: string, maxHops?: number, filter?: Record): Promise; /** * Compile context fragments into a token-budgeted, provenance-audited * prompt context — deterministic, no LLM, running the same compiler as the * MCP server and the Node binding, in the browser. Request and result use * the MCP `compile_context` wire shape; every id field crosses as a * decimal string. * * In-memory semantics: externalized sources and savings events live in * this session's store — `ctx://source/` handles resolve only within the * current browser session. */ compileContext(request: CompileContextRequest): Promise; /** * One-call shortcut over {@link compileContext} for a raw agent-session * transcript: deterministically segments it into turns (plain * marker-based — `System:`/`User:`/`Human:`/`Assistant:`/`AI:`/`Tool:`/ * `### User`/`### Assistant` — or JSONL, one line per turn) and, within * each turn, into code/log/body sub-segments (fenced code blocks stay * atomic; runs of 8+ log-like lines collapse), then compiles the result * exactly like {@link compileContext}. Only an inline `transcript` is * accepted — the wedge has no filesystem, so there is no `path` variant. * Resolves to `{ context, segmentation }`: `context` is byte-compatible * with {@link compileContext}'s own output; `segmentation` is the * detected format plus one audit entry (turn, role, kind, byte range, * `fragment_id` — a decimal string) per segment. * * In-memory semantics: same as {@link compileContext} — externalized * sources and savings events live only in this session's store. */ compileTranscript(request: CompileTranscriptRequest): Promise; /** * Explain why one fragment of a {@link compileContext} / * {@link compileTranscript} request was preserved, abstracted, * externalized, dropped, or cached. Compilation is deterministic, so * `request` is re-compiled (event/source recording forced off) and the * matching decision is returned — no server-side state needed. * `fragmentIndex` (0-based position in `request.fragments`), when given, * TAKES PRIORITY over `fragmentId` for locating the decision: a shared * content-addressed id (byte-identical fragments) otherwise always * resolves to the deduplication survivor's decision. */ explainCompilation(request: CompileContextRequest, fragmentId: string, fragmentIndex?: number): Promise; /** * Aggregate the token (and cost) savings of past {@link compileContext} / * {@link compileTranscript} calls, optionally narrowed to one `project`. * * In-memory semantics: same as {@link compileContext} — the aggregated * events live only in this session's store. */ contextSavings(project?: string): Promise; /** * Suggest a starting `token_budget` for {@link compileContext} / * {@link compileTranscript}, for a named target model — looked up in a * static, committed model-name to context-window table (dated "as of", * NEVER a network call). Pass `reserveTokens` (default 0) to reserve room * for the response. `window`/`suggested_budget` come back `null` when the * model is not in the table — an honest "unknown", never a guess. */ suggestBudget(targetModel: string, reserveTokens?: number): Promise; /** * Fetch back the exact original content — and media, when the fragment * carried one — behind a `ctx://source/` handle from a * {@link compileContext} result: what was externalized or partially * packed is recoverable, not lost. Same wire shape as the Node binding's * own `retrieveContextSource`. * * In-memory semantics: the handle resolves only within this session's * store — see {@link compileContext}'s doc comment. */ retrieveContextSource(handle: string): Promise; /** * Persist the agent's distilled working state under `project` + `session` * (idempotent upsert: saving again replaces the previous state), for * later resumption (#1517, option 2). Same wire shape as the Node * binding's `saveWorkingContext`. Resolves to the stored fact id as a * decimal string. * * **In-memory semantics**: like {@link compileContext}, this is backed * entirely by this session's in-memory wasm store — there is no * filesystem or IndexedDB persistence behind this binding. A "saved" * working context disappears the moment this `MemoryService` instance * (and the page/worker that created it) is gone. This is useful to carry * state between two calls made within the SAME page load (e.g. across two * {@link compileContext} calls), not to resume a session after a reload — * that would need a real browser-storage backend, which does not exist * yet. */ saveWorkingContext(project: string, session: string, working: WorkingContext): Promise; /** * The resumption envelope for `project` + `session` — the start-of-session * mirror of {@link saveWorkingContext} (#1517, option 2). * `loadWorkingContext` returns `{found, working, other_sessions}`, the same * shape the MCP `load_working_context` tool serves. * * **BREAKING (`velesdb-memory` 0.12.0, relayed by the next * `@wiscale/velesdb-sdk` release)**: this used to resolve * `WorkingContext | null`. Read `.working` for the previous value, and * `.other_sessions` for what the bare form could not express — that * `session` may have been a typo which missed a session that does exist. * See {@link LoadedWorkingContext}. * * **Rejects** with a {@link ConnectionError} when the resolved * `@wiscale/velesdb-wasm` build predates the envelope and hands back the * bare form. The floor in `package.json` admits such builds, and the * method exists on them, so nothing else would notice. * * **In-memory semantics**: see {@link saveWorkingContext}'s doc comment — * this only ever resolves what THIS session's in-memory store still * holds; nothing persists across a page reload. */ loadWorkingContext(project: string, session: string): Promise; /** * Every session ever saved under `project`'s working-context index, * most-recently-saved first — empty (never an error) when the project * never saved anything (#1517, option 2). * * **In-memory semantics**: see {@link saveWorkingContext}'s doc comment — * reflects only what this session's in-memory store currently holds, * never a cross-session/browser-restart view. */ listWorkingContexts(project: string): Promise; } /** * VelesQL Query Builder (EPIC-012/US-004) * * Fluent, type-safe API for building VelesQL queries. * * @example * ```typescript * import { velesql } from '@wiscale/velesdb-sdk'; * * const query = velesql() * .match('d', 'Document') * .nearVector('$q', embedding) * .andWhere('d.category = $cat', { cat: 'tech' }) * .limit(20) * .toVelesQL(); * ``` * * @packageDocumentation */ /** Direction for relationship traversal */ type RelDirection = 'outgoing' | 'incoming' | 'both'; /** Options for relationship patterns */ interface RelOptions { direction?: RelDirection; minHops?: number; maxHops?: number; } /** Options for vector NEAR clause */ interface NearVectorOptions { topK?: number; } /** * Fusion strategies valid for `NEAR_FUSED` (multi-vector) search. * * Deliberately a STRICT subset of {@link FusionStrategy}: only `rrf`, * `average`, and `maximum` are meaningful when fusing N homogeneous query * vectors. `weighted`/`relative_score` have no per-branch weights to apply * here and the core silently downgrades them to RRF (the "weighted -> RRF" * trap). Restricting the type makes that misuse a COMPILE error. */ type NearFusedStrategy = 'rrf' | 'average' | 'maximum'; /** Options for the {@link VelesQLBuilder.nearFused} multi-vector clause */ interface NearFusedOptions { /** Fusion strategy (default: `rrf`). Only `rrf`/`average`/`maximum` allowed. */ strategy?: NearFusedStrategy; } /** Fusion configuration */ interface FusionOptions { strategy: FusionStrategy; k?: number; vectorWeight?: number; graphWeight?: number; } /** Internal state for the query builder */ interface BuilderState { matchClauses: string[]; /** SELECT-mode source table/collection (set via {@link VelesQLBuilder.from}). */ fromClause?: string; /** SELECT-mode projection columns (set via {@link VelesQLBuilder.select}). */ selectColumns?: string[]; whereClauses: string[]; whereOperators: string[]; params: Record; limitValue?: number; /** topK from {@link VelesQLBuilder.nearVector}, applied as a LIMIT fallback. */ topKValue?: number; offsetValue?: number; orderByClause?: string; returnClause?: string; fusionOptions?: FusionOptions; currentNode?: string; pendingRel?: { type: string; alias?: string; options?: RelOptions; }; } /** * VelesQL Query Builder * * Immutable builder for constructing VelesQL queries with type safety. */ declare class VelesQLBuilder { private readonly state; constructor(state?: Partial); private clone; /** * Start a MATCH clause with a node pattern * * @param alias - Node alias (e.g., 'n', 'person') * @param label - Optional node label(s) */ match(alias: string, label?: string | string[]): VelesQLBuilder; /** * Start a SELECT-mode query against a collection/table. * * Use this for vector search and hybrid (NEAR + MATCH / fusion) queries, * which are expressed as `SELECT ... FROM WHERE ...` in * VelesQL — not as graph `MATCH` patterns. When `from()` is set the * builder emits a `SELECT` statement instead of a `MATCH`. * * @param collection - Source collection/table name * @param alias - Optional alias (kept for `WHERE`/`ORDER BY` references) * * @example * ```typescript * velesql() * .from('documents', 'd') * .nearVector('$q', embedding) * .andWhere('d.category = $cat', { cat: 'tech' }) * .orderBy('score', 'DESC') * .limit(10) * .toVelesQL(); * // => "SELECT * FROM documents WHERE vector NEAR $q AND d.category = $cat ORDER BY score DESC LIMIT 10" * ``` */ from(collection: string, alias?: string): VelesQLBuilder; /** * Set the SELECT projection columns (SELECT mode only). * * Without this the query projects `*`. * * @param columns - Column expressions to project */ select(columns: string[]): VelesQLBuilder; /** * Add a relationship pattern * * @param type - Relationship type (e.g., 'KNOWS', 'FOLLOWS') * @param alias - Optional relationship alias * @param options - Relationship options (direction, hops) */ rel(type: string, alias?: string, options?: RelOptions): VelesQLBuilder; /** * Complete a relationship pattern with target node * * @param alias - Target node alias * @param label - Optional target node label(s) */ to(alias: string, label?: string | string[]): VelesQLBuilder; /** * Add a WHERE clause * * @param condition - WHERE condition * @param params - Optional parameters * * @example * ```typescript * // Substring matching with CONTAINS_TEXT * velesql() * .match('d', 'Document') * .where("content CONTAINS_TEXT 'keyword'") * .limit(10) * .toVelesQL(); * ``` */ where(condition: string, params?: Record): VelesQLBuilder; /** * Add an AND WHERE clause * * @param condition - WHERE condition * @param params - Optional parameters */ andWhere(condition: string, params?: Record): VelesQLBuilder; /** * Add an OR WHERE clause * * @param condition - WHERE condition * @param params - Optional parameters */ orWhere(condition: string, params?: Record): VelesQLBuilder; /** * Add a vector NEAR clause for similarity search * * @param paramName - Parameter name (e.g., '$query', '$embedding') * @param vector - Vector data * @param options - NEAR options (topK) */ nearVector(paramName: string, vector: number[] | Float32Array, options?: NearVectorOptions): VelesQLBuilder; /** * Add a multi-vector `NEAR_FUSED` clause for fused similarity search. * * Fuses several query vectors into one ranking. The strategy is typed as * {@link NearFusedStrategy} (`rrf` | `average` | `maximum`) so the * `weighted`/`relative_score` trap — which the engine silently downgrades * to RRF — is a COMPILE-TIME error rather than a silent surprise. * * @param paramNames - Parameter names, one per query vector (e.g. `['$a', '$b']`) * @param vectors - One vector per param name (same order) * @param options - Fusion options (strategy) * * @example * ```typescript * velesql() * .from('docs') * .nearFused(['$a', '$b'], [vecA, vecB], { strategy: 'average' }) * .limit(10) * .toVelesQL(); * // => "SELECT * FROM docs WHERE vector NEAR_FUSED [$a, $b] USING FUSION 'average' LIMIT 10" * ``` */ nearFused(paramNames: string[], vectors: Array, options?: NearFusedOptions): VelesQLBuilder; /** Append a WHERE condition (AND-joined) and merge params. */ private appendCondition; /** * Add LIMIT clause * * @param value - Maximum number of results */ limit(value: number): VelesQLBuilder; /** * Add OFFSET clause * * @param value - Number of results to skip */ offset(value: number): VelesQLBuilder; /** * Add ORDER BY clause * * @param field - Field to order by * @param direction - Sort direction (ASC or DESC) */ orderBy(field: string, direction?: 'ASC' | 'DESC'): VelesQLBuilder; /** * Add RETURN clause with specific fields * * @param fields - Fields to return (array or object with aliases) */ return(fields: string[] | Record): VelesQLBuilder; /** * Add RETURN * clause */ returnAll(): VelesQLBuilder; /** * Set fusion strategy for hybrid queries * * @param strategy - Fusion strategy * @param options - Fusion parameters */ fusion(strategy: FusionStrategy, options?: { k?: number; vectorWeight?: number; graphWeight?: number; }): VelesQLBuilder; /** * Get the fusion options */ getFusionOptions(): FusionOptions | undefined; /** * Get all parameters */ getParams(): Record; /** * Build the VelesQL query string. * * Emits a `SELECT` statement when {@link from} was called, otherwise a * graph `MATCH` statement. Both clause orders are dictated by the VelesQL * grammar so the output round-trips through the core parser: * - SELECT: `SELECT … FROM … [WHERE …] [ORDER BY …] [LIMIT] [OFFSET] [USING FUSION(…)]` * - MATCH: `MATCH … [WHERE …] RETURN … [ORDER BY …] [LIMIT]` * (`RETURN` is mandatory; `MATCH` supports no `OFFSET`.) */ toVelesQL(): string; /** Resolve the effective LIMIT, falling back to a `nearVector({topK})`. */ private resolveLimit; private buildSelect; private buildMatch; /** Render a real `USING FUSION(...)` clause from fusion options. */ private buildFusionClause; private formatLabel; private formatRelationship; private formatHops; private buildWhereClause; } /** * Create a new VelesQL query builder * * @example * ```typescript * const query = velesql() * .match('n', 'Person') * .where('n.age > 21') * .limit(10) * .toVelesQL(); * // => "MATCH (n:Person) WHERE n.age > 21 LIMIT 10" * ``` */ declare function velesql(): VelesQLBuilder; /** * VelesDB SearchQuality → REST wire format * * Helper that converts the TypeScript `SearchQuality` type into the * `{ mode, ef_search }` fragment expected by `velesdb-server`'s * `SearchRequest` body. The server supports named presets * (`fast | balanced | accurate | perfect | autotune`) plus two * template-literal forms: * - `custom:` — explicit HNSW `ef_search` override * - `adaptive::` — recall-target adaptive loop * * The helper preserves the string verbatim and lets the server parse * it via `velesdb_core::api_types::mode_to_search_quality`. This * keeps the wire contract in one place (the Rust parser) so the TS * SDK does not duplicate the variant parsing logic. * * @packageDocumentation */ /** * Fragment spliced into a `SearchRequest` body. Only `mode` is set * today — the Rust parser resolves `custom:` and * `adaptive::` server-side and populates `ef_search` from * the template payload. Callers that need a raw `ef_search` override * should pass `SearchOptions.k` and use `'custom:'`. */ interface SearchQualityWire { /** Search mode preset or template string (see module docs). */ mode?: string; } /** * Convert a `SearchQuality` value into the REST wire fragment. * * Returns an empty object `{}` when the caller passes `undefined`, * so spreading the result into a request body is safe and produces * no `mode` key at all (leaving the server free to apply its * configured default quality). */ declare function searchQualityToMode(quality: SearchQuality | undefined): SearchQualityWire; /** * VelesDB Typed Error Hierarchy * * One TypeScript class per `velesdb_core::error::Error` variant, preserving * the verbatim `VELES-XXX` code for ergonomic catch-by-instance narrowing. * * Motivation: the pre-v1.13 SDK mapped all server errors to a handful of * generic classes (`NotFoundError`, `VelesDBError`) and clobbered the real * `VELES-XXX` code with strings like `'NOT_FOUND'`. Client code had no way * to distinguish "collection not found" (VELES-002) from "edge not found" * (VELES-020) without string-sniffing the message. This module fixes that. * * @example Catch by specific class * ```typescript * try { * await db.search('docs', vec, { k: 10 }); * } catch (e) { * if (e instanceof CollectionNotFoundError) { ... } * else if (e instanceof DimensionMismatchError) { ... } * else if (e instanceof VelesError) { ... } // catches any VELES-XXX * else throw e; // not ours, rethrow * } * ``` * * @packageDocumentation */ /** * Base class for every server-originated VelesDB error carrying a * `VELES-XXX` code. All 36 typed sub-classes extend this. * * Also a direct sub-class of `VelesDBError` so that legacy handlers * that catch `VelesDBError` continue to receive typed errors too. */ declare class VelesError extends VelesDBError { constructor(message: string, code: string, cause?: Error); } /** Collection already exists (VELES-001). */ declare class CollectionExistsError extends VelesError { constructor(message: string); } /** Collection not found (VELES-002). */ declare class CollectionNotFoundError extends VelesError { constructor(message: string); } /** Point with the given ID not found (VELES-003). */ declare class PointNotFoundError extends VelesError { constructor(message: string); } /** Vector dimension mismatch (VELES-004). */ declare class DimensionMismatchError extends VelesError { constructor(message: string); } /** Invalid vector (NaN, wrong length, etc.) (VELES-005). */ declare class InvalidVectorError extends VelesError { constructor(message: string); } /** Storage layer error (mmap, WAL, I/O) (VELES-006). */ declare class StorageError extends VelesError { constructor(message: string); } /** HNSW / BM25 / secondary index error (VELES-007). */ declare class IndexError extends VelesError { constructor(message: string); } /** Index files corrupted and need rebuild (VELES-008). */ declare class IndexCorruptedError extends VelesError { constructor(message: string); } /** Configuration error (invalid settings) (VELES-009). */ declare class ConfigError extends VelesError { constructor(message: string); } /** VelesQL parse or execution error (VELES-010). */ declare class QueryError extends VelesError { constructor(message: string); } /** Low-level I/O error (wraps `std::io::Error`) (VELES-011). */ declare class IoError extends VelesError { constructor(message: string); } /** Serialization / deserialization error (VELES-012). */ declare class SerializationError extends VelesError { constructor(message: string); } /** Internal error — please report if encountered (VELES-013). */ declare class InternalError extends VelesError { constructor(message: string); } /** Vector not allowed on metadata-only collection (VELES-014). */ declare class VectorNotAllowedError extends VelesError { constructor(message: string); } /** Vector search not supported on metadata-only collection (VELES-015). */ declare class SearchNotSupportedError extends VelesError { constructor(message: string); } /** Vector required for vector collection (VELES-016). */ declare class VectorRequiredError extends VelesError { constructor(message: string); } /** Schema validation error (VELES-017). */ declare class SchemaValidationError extends VelesError { constructor(message: string); } /** Graph operation not supported on this collection type (VELES-018). */ declare class GraphNotSupportedError extends VelesError { constructor(message: string); } /** Edge with the given ID already exists (VELES-019). */ declare class EdgeExistsError extends VelesError { constructor(message: string); } /** Edge with the given ID not found (VELES-020). */ declare class EdgeNotFoundError extends VelesError { constructor(message: string); } /** Invalid edge label (empty, too long, forbidden chars) (VELES-021). */ declare class InvalidEdgeLabelError extends VelesError { constructor(message: string); } /** Node with the given ID not found (VELES-022). */ declare class NodeNotFoundError extends VelesError { constructor(message: string); } /** Numeric overflow / cast truncation (VELES-023). */ declare class OverflowError extends VelesError { constructor(message: string); } /** Column store schema or primary-key validation failed (VELES-024). */ declare class ColumnStoreError extends VelesError { constructor(message: string); } /** GPU parameter validation or operation failure (VELES-025). */ declare class GpuError extends VelesError { constructor(message: string); } /** Epoch mismatch — stale mmap guard, not recoverable (VELES-026). */ declare class EpochMismatchError extends VelesError { constructor(message: string); } /** Guard-rail violation: timeout, depth, cardinality, memory, rate limit (VELES-027). */ declare class GuardRailError extends VelesError { constructor(message: string); } /** Invalid quantizer config (PQ subspaces, empty training set, etc.) (VELES-028). */ declare class InvalidQuantizerConfigError extends VelesError { constructor(message: string); } /** Quantizer training failed (convergence, insufficient data) (VELES-029). */ declare class TrainingFailedError extends VelesError { constructor(message: string); } /** Sparse index error (VELES-030). */ declare class SparseIndexError extends VelesError { constructor(message: string); } /** Database already locked by another process (VELES-031). */ declare class DatabaseLockedError extends VelesError { constructor(message: string); } /** Vector dimension outside the valid range (VELES-032). */ declare class InvalidDimensionError extends VelesError { constructor(message: string); } /** Memory allocation failure (out of memory / invalid layout) (VELES-033). */ declare class AllocationFailedError extends VelesError { constructor(message: string); } /** Collection name contains forbidden characters or path separators (VELES-034). */ declare class InvalidCollectionNameError extends VelesError { constructor(message: string); } /** CSR snapshot build failed (allocation failure during rebuild) (VELES-035). */ declare class SnapshotBuildFailedError extends VelesError { constructor(message: string); } /** Collection was created with a newer schema version than this binary supports (VELES-036). */ declare class IncompatibleSchemaVersionError extends VelesError { constructor(message: string); } /** * Every VELES code known to this SDK version, in ascending order. * * Used by tests to verify the 36-code contract and by tooling to emit * doc/type metadata. */ declare const VELES_ERROR_CODES: readonly ["VELES-001", "VELES-002", "VELES-003", "VELES-004", "VELES-005", "VELES-006", "VELES-007", "VELES-008", "VELES-009", "VELES-010", "VELES-011", "VELES-012", "VELES-013", "VELES-014", "VELES-015", "VELES-016", "VELES-017", "VELES-018", "VELES-019", "VELES-020", "VELES-021", "VELES-022", "VELES-023", "VELES-024", "VELES-025", "VELES-026", "VELES-027", "VELES-028", "VELES-029", "VELES-030", "VELES-031", "VELES-032", "VELES-033", "VELES-034", "VELES-035", "VELES-036"]; /** Union type of every known VELES code. */ type VelesErrorCode = (typeof VELES_ERROR_CODES)[number]; /** * Instantiate the correct typed error class from a server-provided * VELES code and message. * * - If `code` matches one of the 36 known VELES-XXX codes, returns * the matching typed sub-class. * - If `code` is an unknown VELES code (e.g. `VELES-999` from a * newer server), returns a generic `VelesError` preserving the * code verbatim — forward-compatible with future core versions. * - If `code` is null/undefined (legacy `error_response` path in * server that omits the code field), returns a generic * `VelesError` with code `'VELES-UNKNOWN'`. * * **Never** fabricates a fake code like `'NOT_FOUND'` — that was the * pre-v1.13 anti-pattern this function exists to replace. */ declare function parseVelesError(code: string | null | undefined, message: string): VelesError; /** * Optional embedding helpers for the VelesDB TypeScript SDK. * * A thin {@link Embedder} interface plus an adapter for OpenAI-compatible * endpoints. The adapter uses the global `fetch` API (Node ≥ 18, browsers, * Deno) and has no additional runtime dependencies. * * @example * ```typescript * import { VelesDB, OpenAIEmbedder } from '@wiscale/velesdb-sdk'; * * const embedder = new OpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY! }); * const db = new VelesDB({ backend: 'wasm' }); * await db.init(); * await db.createCollection('docs', { dimension: embedder.dimension ?? 1536 }); * const vectors = await embedder.embed(['hello world', 'vector search']); * ``` */ interface Embedder { /** Embedding dimension, or `0` if not yet known (determined after first call). */ readonly dimension: number; embed(texts: string[]): Promise; } interface OpenAIEmbedderOptions { model?: string; apiKey: string; /** Override the base URL for Azure OpenAI, vLLM, or any compatible endpoint. */ baseUrl?: string; /** Request a specific output dimension (requires a model that supports it). */ dimensions?: number; } declare class OpenAIEmbedder implements Embedder { private readonly model; private readonly apiKey; private readonly baseUrl; private readonly requestedDimensions; dimension: number; constructor(options: OpenAIEmbedderOptions); embed(texts: string[]): Promise; } export { type ActualStats, type AddEdgeRequest, AgentMemoryClient, type AgentMemoryConfig, type AggregateQueryOptions, type AggregateResponse, type AggregationQueryResponse, AllocationFailedError, type AlterCollectionOptions, type AsyncIndexBuilderOptions, type BackendType, BackpressureError, type CapabilityMap, type Collection, type CollectionConfig, type CollectionConfigResponse, CollectionExistsError, CollectionNotFoundError, type CollectionSanityChecks, type CollectionSanityDiagnostics, type CollectionSanityResponse, type CollectionStatsResponse, type CollectionType, type ColumnStatsDetail, ColumnStoreError, type CompareOp, type Condition, ConfigError, ConnectionError, type CreateIndexOptions, DatabaseLockedError, type DeferredIndexerOptions, type DegreeResponse, DimensionMismatchError, type DistanceMetric, EdgeExistsError, EdgeNotFoundError, type EdgesResponse, type Embedder, type EpisodicEvent, type EpisodicRecord, EpochMismatchError, type ExplainCost, type ExplainFeatures, type ExplainPlanStep, type ExplainResponse, type Filter, type FilterInput, type FusionOptions, type FusionStrategy, type GetEdgesOptions, type GetNodeEdgesOptions, GpuError, type GraphCollectionConfig, type GraphEdge, type GraphNodeId, GraphNotSupportedError, type GraphSchemaMode, type GraphSearchRequest, type GraphSearchResponse, type GraphSearchResultItem, GuardRailError, type GuardRailsConfigResponse, type GuardRailsUpdateRequest, type HnswParams, type IVelesDBBackend, IncompatibleSchemaVersionError, IndexCorruptedError, IndexError, type IndexInfo, type IndexType, InternalError, InvalidCollectionNameError, InvalidDimensionError, InvalidEdgeLabelError, InvalidQuantizerConfigError, InvalidVectorError, IoError, type JsonValue, type ListNodesResponse, type MatchQueryOptions, type MatchQueryResponse, type MatchQueryResultItem, type MemoryColumnFilter, type MemoryDatedRecall, type MemoryEdge, type MemoryExplanation, type MemoryFusionOptions, type MemoryLink, type MemoryNode, type MemoryRecollection, MemoryService, type MultiQuerySearchOptions, type NearFusedOptions, type NearFusedStrategy, type NearVectorOptions, NodeNotFoundError, type NodePayloadResponse, type NodeStats, NotFoundError, OpenAIEmbedder, type OpenAIEmbedderOptions, OverflowError, PointNotFoundError, type PqTrainOptions, type ProceduralPattern, type QueryApiResponse, QueryError, type QueryOptions, type QueryResponse, type QueryResult, type QueryStats, REST_CAPABILITIES, type RebuildIndexResponse, type RelDirection, type RelOptions, type RelateRequest, type RelateResponse, type RelationEdge, type RelationsResponse, RestBackend, type RestPointId, SchemaValidationError, type ScrollRequest, type ScrollResponse, SearchNotSupportedError, type SearchOptions, type SearchQuality, type SearchQualityWire, type SearchResult, type SemanticEntry, SerializationError, SnapshotBuildFailedError, SparseIndexError, type SparseSearchNamedOptions, type SparseVector, StorageError, type StorageMode, type StreamUpsertResponse, type StreamingConfig, TrainingFailedError, type TraversalResultItem, type TraversalStats, type TraverseParallelRequest, type TraverseRequest, type TraverseResponse, VELES_ERROR_CODES, ValidationError, type VectorDocument, VectorNotAllowedError, VectorRequiredError, VelesDB, type VelesDBConfig, VelesDBError, VelesError, type VelesErrorCode, VelesQLBuilder, WASM_CAPABILITIES, WasmBackend, f, isTypedFilter, normalizeFilter, parseVelesError, searchQualityToMode, velesql };