@ponraaj/dimple-sdk 0.0.0-alpha.7 → 0.0.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,35 +1,10 @@
1
- /**
2
- * First-use auto-install of the OPTIONAL `@huggingface/transformers` peer.
3
- *
4
- * `@huggingface/transformers` is an optional peer (its tree pulls the
5
- * `sharp` + `onnxruntime-node` postinstall scripts that abort npm 11
6
- * installs). When the config declares a `transformers` provider model,
7
- * the intent is explicit — so the FIRST local-embed use installs the
8
- * package automatically with the project's own package manager, instead
9
- * of failing with a manual step.
10
- *
11
- * Safety notes:
12
- * - The install is scoped to the detected project root (the manifest's
13
- * directory) and uses the manager the project already uses.
14
- * - EVERY install runs `--ignore-scripts` (npm/pnpm/yarn) or bun's
15
- * default script-blocking — verified harmless: the onnxruntime-node
16
- * binaries ship in the package; its postinstall is not required for
17
- * embedding, and sharp is never loaded for text embeddings.
18
- * - Failure (offline, restricted env) is a typed EmbeddingError with the
19
- * manual command — never a crash.
20
- */
21
- export type PackageManager = "bun" | "npm" | "pnpm" | "yarn";
22
- export interface InstallTarget {
23
- readonly pm: PackageManager;
24
- readonly root: string;
25
- }
26
- /** Detect the project's package manager by walking UP from `cwd` for a
27
- * lockfile (bun.lock/bun.lockb → bun, package-lock.json → npm,
28
- * pnpm-lock.yaml → pnpm, yarn.lock → yarn). Falls back to bun + cwd. */
29
- export declare const detectPackageManager: (cwd: string) => InstallTarget;
30
- /** The install argv for a manager. `--ignore-scripts` on npm/pnpm/yarn:
31
- * the blocked postinstalls are proven unnecessary for embedding (bun
32
- * blocks them by default already). */
1
+ import { type PackageManager } from "./internal/installer/index.js";
2
+ export type { InstallTarget, PackageManager } from "./internal/installer/index.js";
3
+ export { detectPackageManager } from "./internal/installer/index.js";
4
+ /** The install argv for a manager with the transformers package (kept for
5
+ * callers/tests that assert the shape). */
33
6
  export declare const installCommand: (pm: PackageManager) => readonly [string, ...string[]];
34
- /** Run the install for the project at `cwd`; rejects on non-zero exit. */
7
+ /** Install transformers at the project root detected from `cwd`. The
8
+ * shared installer kills the child on timeout and dedups concurrent
9
+ * first-use installs; failures reject with the manual command. */
35
10
  export declare const installTransformers: (cwd: string) => Promise<void>;
@@ -0,0 +1,26 @@
1
+ export type PackageManager = "bun" | "npm" | "pnpm" | "yarn";
2
+ export interface InstallTarget {
3
+ readonly pm: PackageManager;
4
+ readonly root: string;
5
+ }
6
+ export declare class InstallerError extends Error {
7
+ constructor(message: string);
8
+ }
9
+ /** Detect the project's package manager by walking UP from `cwd` for a
10
+ * lockfile. NO lockfile → npm (the most universal — a bun fallback broke
11
+ * Node-only machines with ENOENT). */
12
+ export declare const detectPackageManager: (cwd: string) => InstallTarget;
13
+ /** The executable name for a manager. win32 ships `.cmd` shims for
14
+ * npm/pnpm/yarn — the bare names fail with ENOENT. */
15
+ export declare const resolveExecutable: (pm: PackageManager, platform?: NodeJS.Platform) => string;
16
+ /** The base install argv for a manager. Scripts are skipped everywhere;
17
+ * pnpm at a workspace root additionally gets `-w`. */
18
+ export declare const installArgs: (pm: PackageManager, packages: readonly string[], root: string) => string[];
19
+ export interface InstallOptions {
20
+ readonly cwd?: string;
21
+ /** Hard deadline; the child is SIGKILLed when it trips (default 5 min). */
22
+ readonly timeoutMs?: number;
23
+ /** Injectable for tests (defaults to process.platform). */
24
+ readonly platform?: NodeJS.Platform;
25
+ }
26
+ export declare const installOptionalPeers: (packages: readonly string[], opts?: InstallOptions) => Promise<void>;
@@ -84,8 +84,12 @@ export interface Interface {
84
84
  readonly listIsolatedMemories: (limit: number, modelKey?: string) => Effect.Effect<readonly Record<string, unknown>[], StoreError>;
85
85
  readonly db: DrizzleDB;
86
86
  readonly tables: StoreTables;
87
- readonly ftsSearch: (query: string, namespace: string, limit: number, topicKeys?: ReadonlyArray<string>, modelKey?: string, contentType?: string | ReadonlyArray<string>) => Effect.Effect<readonly Record<string, unknown>[], StoreError>;
88
- readonly vectorSearch: (query: ReadonlyArray<number>, namespace: string, limit: number, model: EmbeddingModelConfig, topicKeys?: ReadonlyArray<string>, contentType?: string | ReadonlyArray<string>) => Effect.Effect<readonly Record<string, unknown>[], StoreError>;
87
+ readonly ftsSearch: (query: string, namespace: string, limit: number, topicKeys?: ReadonlyArray<string>, modelKey?: string, contentType?: string | ReadonlyArray<string>,
88
+ /** Include the 384-float `embedding` blob per row (default false —
89
+ * search results never need vectors; write paths read them via
90
+ * fetchMemoryVectors). */
91
+ includeEmbedding?: boolean) => Effect.Effect<readonly Record<string, unknown>[], StoreError>;
92
+ readonly vectorSearch: (query: ReadonlyArray<number>, namespace: string, limit: number, model: EmbeddingModelConfig, topicKeys?: ReadonlyArray<string>, contentType?: string | ReadonlyArray<string>, includeEmbedding?: boolean) => Effect.Effect<readonly Record<string, unknown>[], StoreError>;
89
93
  readonly sweep: (namespace: string) => Effect.Effect<SweepResult, StoreError>;
90
94
  /** The DB's tables + columns (`dimple db-schema` surface). */
91
95
  readonly listSchema: () => Effect.Effect<ReadonlyArray<{
@@ -109,11 +113,26 @@ export interface Interface {
109
113
  readonly graphNeighbors: (kind: "memory" | "topic" | "concept", id: string, opts?: GraphNeighborsOptions) => Effect.Effect<readonly Record<string, unknown>[], StoreError>;
110
114
  readonly ensureVectorTable: (model: EmbeddingModelConfig) => Effect.Effect<void, StoreError>;
111
115
  readonly insertVector: (memoryId: string, vector: ReadonlyArray<number>, model: EmbeddingModelConfig) => Effect.Effect<void, StoreError>;
116
+ /** Batch variant of `insertVector` — one multi-row statement (bulk
117
+ * ingest: per-memory statements dominate the write path). */
118
+ readonly insertVectors: (entries: ReadonlyArray<{
119
+ readonly memoryId: string;
120
+ readonly vector: ReadonlyArray<number>;
121
+ }>, model: EmbeddingModelConfig) => Effect.Effect<void, StoreError>;
112
122
  readonly deleteVector: (memoryId: string, dimensions: number) => Effect.Effect<void, StoreError>;
113
123
  readonly ensureTopicVectorTable: (model: EmbeddingModelConfig) => Effect.Effect<void, StoreError>;
114
124
  readonly upsertTopicVector: (topicKey: string, sumVector: ReadonlyArray<number>, model: EmbeddingModelConfig) => Effect.Effect<void, StoreError>;
125
+ /** Batch variant of `upsertTopicVector` — one multi-row statement (the
126
+ * bulk-routing path: sequential per-key upserts dominate batch ingest). */
127
+ readonly upsertTopicVectors: (entries: ReadonlyArray<{
128
+ readonly topicKey: string;
129
+ readonly sumVector: ReadonlyArray<number>;
130
+ }>, model: EmbeddingModelConfig) => Effect.Effect<void, StoreError>;
115
131
  readonly deleteTopicVectors: (model: EmbeddingModelConfig) => Effect.Effect<void, StoreError>;
116
132
  readonly fetchTopicVectors: (model: EmbeddingModelConfig) => Effect.Effect<ReadonlyArray<TopicVectorRow>, StoreError>;
133
+ /** Single-row variant — the forget path's per-ancestor maintenance
134
+ * re-read the WHOLE table per level before (O(depth × N) decodes). */
135
+ readonly fetchTopicVector: (topicKey: string, model: EmbeddingModelConfig) => Effect.Effect<TopicVectorRow | undefined, StoreError>;
117
136
  readonly fetchMemoryVectors: (memoryIds: ReadonlyArray<string>, model: EmbeddingModelConfig) => Effect.Effect<ReadonlyArray<MemoryVectorRow>, StoreError>;
118
137
  readonly listMemoryIds: (model: EmbeddingModelConfig) => Effect.Effect<ReadonlyArray<string>, StoreError>;
119
138
  }
@@ -1,5 +1,5 @@
1
1
  import { Context, Effect } from "effect";
2
- import type { MemoryUnit, MemoryEvent, WriteMemoryInput, SweepResult, Concept } from "./models.ts";
2
+ import type { MemoryUnit, MemoryEvent, WriteMemoryInput, SweepResult, Concept, ScoredMemory } from "./models.ts";
3
3
  import type { StoreError, NotFound, DuplicateActiveKey } from "./error.ts";
4
4
  import type { TopicError } from "./topics/errors.ts";
5
5
  import type { MaintenanceOutcome, RebalanceOutcome } from "./topics/maintenance.ts";
@@ -65,6 +65,11 @@ export interface ExplainResult {
65
65
  }
66
66
  export interface Interface {
67
67
  readonly write: (input: WriteMemoryInput) => Effect.Effect<MemoryUnit, StoreError | DuplicateActiveKey>;
68
+ /** Bulk write: batch insert in ONE transaction (all-or-nothing; a
69
+ * duplicate logical key fails the whole batch with DuplicateActiveKey).
70
+ * The per-write graph candidate scan is NOT part of this — pair with
71
+ * `updateEmbedding(..., { scanCandidates: false })` for bulk ingest. */
72
+ readonly writeMany: (inputs: readonly WriteMemoryInput[]) => Effect.Effect<readonly MemoryUnit[], StoreError | DuplicateActiveKey>;
68
73
  /** Upsert for the index path — the identity rule (same logical key ⇒
69
74
  * confirmed `memory_supersedes`) made reachable for ACTIVE keys: demote
70
75
  * the active holder of the key (if any), write the new unit, and link
@@ -105,6 +110,10 @@ export interface Interface {
105
110
  readonly contentType?: string | ReadonlyArray<string>;
106
111
  /** `false` suppresses the per-leg audit row (fused-row callers). */
107
112
  readonly audit?: boolean;
113
+ /** Include the 384-float embedding on results (default false). */
114
+ readonly includeEmbedding?: boolean;
115
+ /** `false` skips the per-leg graph augmentation (fused-row callers). */
116
+ readonly augment?: boolean;
108
117
  }) => Effect.Effect<ReadonlyArray<AugmentedMemory>, StoreError>;
109
118
  readonly searchVector: (query: ReadonlyArray<number>, namespace: string, limit: number, opts?: {
110
119
  readonly topicKeys?: ReadonlyArray<string>;
@@ -115,7 +124,16 @@ export interface Interface {
115
124
  readonly contentType?: string | ReadonlyArray<string>;
116
125
  /** `false` suppresses the per-leg audit row (fused-row callers). */
117
126
  readonly audit?: boolean;
127
+ /** Include the 384-float embedding on results (default false). */
128
+ readonly includeEmbedding?: boolean;
129
+ /** `false` skips the per-leg graph augmentation (fused-row callers). */
130
+ readonly augment?: boolean;
118
131
  }) => Effect.Effect<ReadonlyArray<AugmentedMemory>, StoreError>;
132
+ /** One-pass graph augmentation over an already-ranked result set (the
133
+ * hybrid path: the per-leg augment passes are skipped and the FUSED set
134
+ * gets one edge fetch + one concept fetch instead of two of each over
135
+ * 2× the rows). */
136
+ readonly augmentSearchResults: (results: ReadonlyArray<ScoredMemory>) => Effect.Effect<ReadonlyArray<AugmentedMemory>, StoreError>;
119
137
  /** The DB's tables + columns (`dimple db-schema` surface). */
120
138
  readonly listSchema: () => Effect.Effect<ReadonlyArray<{
121
139
  readonly table: string;
@@ -139,7 +157,23 @@ export interface Interface {
139
157
  readonly forget: (id: string) => Effect.Effect<void, NotFound | StoreError>;
140
158
  readonly sweep: (namespace: string) => Effect.Effect<SweepResult, StoreError>;
141
159
  readonly events: (memoryId: string) => Effect.Effect<readonly MemoryEvent[], StoreError>;
142
- readonly updateEmbedding: (id: string, embedding: ReadonlyArray<number>, model: string) => Effect.Effect<void, NotFound | StoreError>;
160
+ readonly updateEmbedding: (id: string, embedding: ReadonlyArray<number>, model: string, options?: {
161
+ readonly scanCandidates?: boolean;
162
+ }) => Effect.Effect<void, NotFound | StoreError>;
163
+ /** Bulk variant of `updateEmbedding` — the writeMany path. One
164
+ * transaction for all memory updates + events, batch vector insert,
165
+ * and `routeInsertMany` (tree read once, all insertions computed in
166
+ * memory, one transaction). For NEW memories: the idempotent re-embed
167
+ * decrement is deliberately NOT part of the batch (use
168
+ * `updateEmbedding` for re-embedding existing routed memories).
169
+ * `scanCandidates` defaults to false-ish via the config: it runs only
170
+ * when explicitly requested AND `graph.enabled` is not false. */
171
+ readonly updateEmbeddingMany: (entries: ReadonlyArray<{
172
+ readonly id: string;
173
+ readonly embedding: ReadonlyArray<number>;
174
+ }>, model: string, options?: {
175
+ readonly scanCandidates?: boolean;
176
+ }) => Effect.Effect<void, StoreError>;
143
177
  readonly findStale: (model: string) => Effect.Effect<readonly string[], StoreError>;
144
178
  readonly createConcept: (name: string, embedding: ReadonlyArray<number>) => Effect.Effect<Concept, StoreError>;
145
179
  readonly getConcept: (id: string) => Effect.Effect<Concept, NotFound | StoreError>;
@@ -88,3 +88,36 @@ export declare const routeInsert: (memoryId: string, vector: ReadonlyArray<numbe
88
88
  topicKey: string;
89
89
  overflow: boolean;
90
90
  }, TopicError | StoreError, DbBackend>;
91
+ /**
92
+ * Batch routing — the bulk-ingest path (`Store.updateEmbeddingMany`).
93
+ *
94
+ * Sequential `routeInsert` re-reads the WHOLE tree (all topics, all
95
+ * relations, all centroid sum-vectors) and commits its own transaction
96
+ * PER UNIT — measured ~42 ms/unit under bulk ingest, dominating the
97
+ * write path. This variant:
98
+ *
99
+ * 1. Reads the tree structure + sum-vectors ONCE.
100
+ * 2. Routes every entry against an IN-MEMORY mirror of the tree state,
101
+ * applying each unit's CF updates locally before the next descent —
102
+ * so the descents are bit-identical to sequential routeInsert calls
103
+ * against the DB (same reads, same writes, same order).
104
+ * 3. Applies ALL membership inserts + topic CF updates in ONE
105
+ * transaction (per-topic deltas accumulated in memory).
106
+ * 4. Writes the derived sum vectors in ONE batched upsert (backend
107
+ * `upsertTopicVectors`), still after commit (backend not
108
+ * transaction-aware — see module docs).
109
+ *
110
+ * Contract differences vs sequential: all-or-nothing (a validation
111
+ * failure or structural corruption rejects the whole batch), and the
112
+ * batch does NOT handle re-embedding (no membership decrement path) —
113
+ * it is for NEW memories; re-embedding existing ones goes through
114
+ * `routeInsert`/`Store.updateEmbedding`.
115
+ */
116
+ export declare const routeInsertMany: (entries: readonly {
117
+ readonly memoryId: string;
118
+ readonly vector: ReadonlyArray<number>;
119
+ }[], model: EmbeddingModelConfig, config: TopicConfig) => Effect.Effect<readonly {
120
+ readonly memoryId: string;
121
+ readonly topicKey: string;
122
+ readonly overflow: boolean;
123
+ }[], TopicError | StoreError, DbBackend>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * In-process execution-completion signals — the event side of `Runtime.wait`.
3
+ *
4
+ * `wait` used to poll the persisted `${jobId}/result` key every 250ms. The
5
+ * engine knows the exact completion moment, so it now notifies a per-
6
+ * executionId set of Deferreds; `wait` races the signal against its poll
7
+ * interval (the poll stays as the fallback for cross-process waits, where
8
+ * the completing engine lives in another process).
9
+ *
10
+ * Plain module-level Map — no Effect service: the signal is a fire-and-
11
+ * forget wakeup, and the subscribers are runtime-layer Deferreds. Cleanup
12
+ * on unsubscribe keeps the map from leaking job ids.
13
+ */
14
+ import { Deferred } from "effect";
15
+ /** Subscribe to one execution's completion. */
16
+ export declare const onExecutionDone: (executionId: string, deferred: Deferred.Deferred<void>) => void;
17
+ /** Unsubscribe (wait's finally — the poll fallback may still be running). */
18
+ export declare const offExecutionDone: (executionId: string, deferred: Deferred.Deferred<void>) => void;
19
+ /** Fire every subscriber's deferred (the engine's completion tap). */
20
+ export declare const notifyExecutionDone: (executionId: string) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponraaj/dimple-sdk",
3
- "version": "0.0.0-alpha.7",
3
+ "version": "0.0.0-alpha.9",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist"