@ponraaj/dimple-sdk 0.0.0-alpha.1
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.
- package/dist/config.d.ts +13 -0
- package/dist/dimple.d.ts +101 -0
- package/dist/errors.d.ts +63 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +8430 -0
- package/dist/indexer.d.ts +43 -0
- package/dist/internal/config/index.d.ts +4 -0
- package/dist/internal/config/loader.d.ts +9 -0
- package/dist/internal/config/schema.d.ts +176 -0
- package/dist/internal/config/service.d.ts +10 -0
- package/dist/internal/core/core.d.ts +95 -0
- package/dist/internal/core/index.d.ts +3 -0
- package/dist/internal/core/layer.d.ts +21 -0
- package/dist/internal/embedder/index.d.ts +4 -0
- package/dist/internal/embedder/openai.d.ts +8 -0
- package/dist/internal/embedder/provider.d.ts +29 -0
- package/dist/internal/embedder/registry.d.ts +10 -0
- package/dist/internal/embedder/transformers.d.ts +18 -0
- package/dist/internal/extractor/code-extractor.d.ts +15 -0
- package/dist/internal/extractor/content-handler.d.ts +17 -0
- package/dist/internal/extractor/index.d.ts +4 -0
- package/dist/internal/extractor/languages/index.d.ts +24 -0
- package/dist/internal/extractor/languages/javascript.d.ts +22 -0
- package/dist/internal/extractor/languages/typescript.d.ts +20 -0
- package/dist/internal/extractor/models/extraction.d.ts +53 -0
- package/dist/internal/llm/dream-classifier.d.ts +14 -0
- package/dist/internal/llm/index.d.ts +4 -0
- package/dist/internal/llm/llm.d.ts +54 -0
- package/dist/internal/llm/provider.d.ts +14 -0
- package/dist/internal/llm/service.d.ts +29 -0
- package/dist/internal/logger/format.d.ts +6 -0
- package/dist/internal/logger/index.d.ts +4 -0
- package/dist/internal/logger/ring.d.ts +33 -0
- package/dist/internal/logger/service.d.ts +50 -0
- package/dist/internal/logger/types.d.ts +39 -0
- package/dist/internal/parser/code-parser.d.ts +12 -0
- package/dist/internal/parser/index.d.ts +7 -0
- package/dist/internal/parser/language-store.d.ts +12 -0
- package/dist/internal/parser/models/parseRequest.d.ts +17 -0
- package/dist/internal/parser/models/treeHandle.d.ts +23 -0
- package/dist/internal/parser/tree-sitter-engine.d.ts +15 -0
- package/dist/internal/retriever/hybrid.d.ts +48 -0
- package/dist/internal/retriever/index.d.ts +3 -0
- package/dist/internal/retriever/rrf.d.ts +11 -0
- package/dist/internal/shared/errors/index.d.ts +2 -0
- package/dist/internal/shared/errors/parser.d.ts +21 -0
- package/dist/internal/shared/errors/wasm.d.ts +28 -0
- package/dist/internal/shared/types/index.d.ts +1 -0
- package/dist/internal/shared/types/language.d.ts +3 -0
- package/dist/internal/store/audit.d.ts +21 -0
- package/dist/internal/store/db-backend.d.ts +111 -0
- package/dist/internal/store/drizzle-schema.d.ts +1 -0
- package/dist/internal/store/error.d.ts +19 -0
- package/dist/internal/store/fnv1a32.d.ts +14 -0
- package/dist/internal/store/generated-migrations.d.ts +15 -0
- package/dist/internal/store/graph/candidates.d.ts +93 -0
- package/dist/internal/store/graph/concepts.d.ts +169 -0
- package/dist/internal/store/graph/dream.d.ts +171 -0
- package/dist/internal/store/graph/errors.d.ts +25 -0
- package/dist/internal/store/graph/index.d.ts +15 -0
- package/dist/internal/store/graph/observability.d.ts +37 -0
- package/dist/internal/store/graph/repair.d.ts +85 -0
- package/dist/internal/store/graph/retrieval-post-pass.d.ts +58 -0
- package/dist/internal/store/graph/traversal.d.ts +39 -0
- package/dist/internal/store/index.d.ts +38 -0
- package/dist/internal/store/libsql-backend.d.ts +18 -0
- package/dist/internal/store/models.d.ts +122 -0
- package/dist/internal/store/schema/graph.d.ts +970 -0
- package/dist/internal/store/schema/index.d.ts +7 -0
- package/dist/internal/store/schema/libsql.d.ts +2356 -0
- package/dist/internal/store/schema/metadata.d.ts +51 -0
- package/dist/internal/store/schema/topics.d.ts +1966 -0
- package/dist/internal/store/service.d.ts +162 -0
- package/dist/internal/store/store.d.ts +70 -0
- package/dist/internal/store/topics/errors.d.ts +39 -0
- package/dist/internal/store/topics/index.d.ts +24 -0
- package/dist/internal/store/topics/jobs.d.ts +149 -0
- package/dist/internal/store/topics/lifecycle.d.ts +126 -0
- package/dist/internal/store/topics/maintenance.d.ts +110 -0
- package/dist/internal/store/topics/observability.d.ts +102 -0
- package/dist/internal/store/topics/query.d.ts +43 -0
- package/dist/internal/store/topics/routing.d.ts +90 -0
- package/dist/internal/store/topics/topic-vectors.d.ts +24 -0
- package/dist/internal/store/topics/tree.d.ts +181 -0
- package/dist/internal/wasm/grammar-store.d.ts +14 -0
- package/dist/internal/wasm/index.d.ts +5 -0
- package/dist/internal/wasm/wasm-cache.d.ts +17 -0
- package/dist/internal/wasm/wasm-downloader.d.ts +10 -0
- package/dist/internal/wasm/wasm-registry.d.ts +16 -0
- package/dist/internal/workflow/config.d.ts +39 -0
- package/dist/internal/workflow/engine.d.ts +54 -0
- package/dist/internal/workflow/errors.d.ts +77 -0
- package/dist/internal/workflow/executor.d.ts +53 -0
- package/dist/internal/workflow/index.d.ts +13 -0
- package/dist/internal/workflow/persistence.d.ts +122 -0
- package/dist/internal/workflow/queue-store.d.ts +5 -0
- package/dist/internal/workflow/queue.d.ts +298 -0
- package/dist/internal/workflow/registry.d.ts +57 -0
- package/dist/internal/workflow/runtime.d.ts +161 -0
- package/dist/make.d.ts +27 -0
- package/package.json +45 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Topic-tree maintenance jobs — underflow (merge/borrow) and sibling
|
|
3
|
+
* rebalance, the structural counterparts of `jobs.ts` splitting.
|
|
4
|
+
*
|
|
5
|
+
* ## mergeOrBorrow
|
|
6
|
+
*
|
|
7
|
+
* B-Tree deletion semantics applied to vector space: when a leaf drops
|
|
8
|
+
* below `minLeafItems`, **borrow first** (cheap, never cascades — the
|
|
9
|
+
* classic B-tree rotation: move the closest movable member from the
|
|
10
|
+
* nearest larger sibling, repeat until valid or no movable members), then
|
|
11
|
+
* **merge** (consumes the sibling; only when `mergedCount ≤ maxLeafItems`
|
|
12
|
+
* so a merge cannot immediately re-overflow into a split — the classic
|
|
13
|
+
* merge→split thrash). If neither is possible, the
|
|
14
|
+
* leaf stays underfilled (logged, status untouched) — lazy-underflow
|
|
15
|
+
* default policy, same as PostgreSQL's no-op on underflow.
|
|
16
|
+
*
|
|
17
|
+
* ## rebalanceSiblings
|
|
18
|
+
*
|
|
19
|
+
* Uneven siblings: when the largest sibling has more than `2×` the
|
|
20
|
+
* smallest, move borderline members (closer to the small centroid than
|
|
21
|
+
* the large one, `manual_lock = 0`, move preserves/improves both radii)
|
|
22
|
+
* from large to small. Gated by the growth-state cooldown
|
|
23
|
+
* (`cooldownUntil` + `rebalanceCooldownMs`) so repeated runs cannot churn.
|
|
24
|
+
*
|
|
25
|
+
* ## Determinism
|
|
26
|
+
*
|
|
27
|
+
* Same DB state + same config ⇒ identical moves: siblings sorted by
|
|
28
|
+
* `topic_key`, centroid scores tie-break lexicographically, candidate
|
|
29
|
+
* members sorted by `memory_id`, all CF math via the O(1) `cfInsert` /
|
|
30
|
+
* `cfRemove` exact updates. Audit timestamps come from the injectable
|
|
31
|
+
* Effect Clock (captured outside the tx closure) — observability only.
|
|
32
|
+
*/
|
|
33
|
+
import { Effect } from "effect";
|
|
34
|
+
import { JobFailure, type Handler, type JobContext } from "./internal/workflow/index.js";
|
|
35
|
+
import type { EmbeddingModelConfig } from "./internal/config/index.js";
|
|
36
|
+
import { Service as DbBackend } from "../db-backend.ts";
|
|
37
|
+
import type { Interface as DbBackendInterface } from "../db-backend.ts";
|
|
38
|
+
import { StoreError } from "../error.ts";
|
|
39
|
+
import type { TopicConfig } from "../schema/topics.ts";
|
|
40
|
+
import type { TopicError } from "./errors.ts";
|
|
41
|
+
/** Result of {@link mergeOrBorrow}: what the maintenance pass did. */
|
|
42
|
+
export type MaintenanceOutcome = {
|
|
43
|
+
readonly action: "none";
|
|
44
|
+
} | {
|
|
45
|
+
readonly action: "borrowed";
|
|
46
|
+
readonly moves: number;
|
|
47
|
+
readonly donor: string;
|
|
48
|
+
} | {
|
|
49
|
+
readonly action: "merged";
|
|
50
|
+
readonly mergedInto: string;
|
|
51
|
+
readonly absorbed: string;
|
|
52
|
+
} | {
|
|
53
|
+
readonly action: "underfilled";
|
|
54
|
+
readonly reason: "no-borrowable" | "merge-would-overflow" | "merge-locked";
|
|
55
|
+
};
|
|
56
|
+
/** Result of {@link rebalanceSiblings}. */
|
|
57
|
+
export type RebalanceOutcome = {
|
|
58
|
+
readonly action: "none";
|
|
59
|
+
readonly reason: "balanced" | "cooldown" | "no-candidates";
|
|
60
|
+
} | {
|
|
61
|
+
readonly action: "rebalanced";
|
|
62
|
+
readonly moves: number;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Underflow maintenance for one leaf: borrow from the nearest larger
|
|
66
|
+
* sibling first, else merge with the nearest sibling (only when the merge
|
|
67
|
+
* stays within `maxLeafItems`), else leave the leaf underfilled (logged).
|
|
68
|
+
* Idempotent: a leaf at or above `minLeafItems` is a no-op.
|
|
69
|
+
*
|
|
70
|
+
* Deterministic: siblings sorted by `topic_key`, nearest by centroid score
|
|
71
|
+
* (lexicographic tie-break), borrowed members chosen closest to the
|
|
72
|
+
* underfilled centroid (tie → smaller `memory_id`), `manual_lock = 1`
|
|
73
|
+
* memberships never auto-move.
|
|
74
|
+
*/
|
|
75
|
+
export declare const mergeOrBorrow: (topicKey: string, model: EmbeddingModelConfig, config: TopicConfig) => Effect.Effect<MaintenanceOutcome, TopicError | StoreError, DbBackend>;
|
|
76
|
+
/**
|
|
77
|
+
* Rebalance uneven siblings under one parent: when the largest sibling has
|
|
78
|
+
* more than `2×` the smallest, move borderline members (closer to the small
|
|
79
|
+
* centroid, `manual_lock = 0`, move preserves/improves both weighted radii)
|
|
80
|
+
* from large to small. Cooldown-gated via growth-state `cooldownUntil`.
|
|
81
|
+
*/
|
|
82
|
+
export declare const rebalanceSiblings: (topicKey: string, model: EmbeddingModelConfig, config: TopicConfig) => Effect.Effect<RebalanceOutcome, TopicError | StoreError, DbBackend>;
|
|
83
|
+
/** Dependencies for {@link topicMergeHandler} / {@link topicRebalanceHandler}. */
|
|
84
|
+
export interface TopicMaintenanceHandlerDeps {
|
|
85
|
+
/** Resolves a model key to its config (the model registry). */
|
|
86
|
+
readonly getModelConfig: (modelKey: string) => EmbeddingModelConfig | undefined;
|
|
87
|
+
/** Tree-shape config for the maintenance decisions. */
|
|
88
|
+
readonly config: TopicConfig;
|
|
89
|
+
/** Backend captured at registration (see {@link topicSplitHandler}). */
|
|
90
|
+
readonly backend?: DbBackendInterface;
|
|
91
|
+
}
|
|
92
|
+
/** The `topic.merge` / `topic.rebalance` handler shape (see jobs.ts). */
|
|
93
|
+
export type TopicMaintenanceHandler = (payload: unknown, ctx: JobContext) => Effect.Effect<unknown, JobFailure, DbBackend>;
|
|
94
|
+
/**
|
|
95
|
+
* Factory for the `topic.merge` job handler: resolves the model, runs
|
|
96
|
+
* {@link mergeOrBorrow}, returns `undefined` (the definition's success
|
|
97
|
+
* schema is `Schema.Void` — the outcome lives in the DB).
|
|
98
|
+
*/
|
|
99
|
+
export declare function topicMergeHandler(deps: TopicMaintenanceHandlerDeps & {
|
|
100
|
+
readonly backend: DbBackendInterface;
|
|
101
|
+
}): Handler;
|
|
102
|
+
export declare function topicMergeHandler(deps: TopicMaintenanceHandlerDeps): TopicMaintenanceHandler;
|
|
103
|
+
/**
|
|
104
|
+
* Factory for the `topic.rebalance` job handler: resolves the model, runs
|
|
105
|
+
* {@link rebalanceSiblings}, returns `undefined`.
|
|
106
|
+
*/
|
|
107
|
+
export declare function topicRebalanceHandler(deps: TopicMaintenanceHandlerDeps & {
|
|
108
|
+
readonly backend: DbBackendInterface;
|
|
109
|
+
}): Handler;
|
|
110
|
+
export declare function topicRebalanceHandler(deps: TopicMaintenanceHandlerDeps): TopicMaintenanceHandler;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Topic-tree observability: metrics, change-log queries, and health checks.
|
|
3
|
+
*
|
|
4
|
+
* All three functions are read-only, Effect-based, take `DbBackend` from the
|
|
5
|
+
* environment, and produce deterministically ordered output (never
|
|
6
|
+
* wall-clock, never randomness):
|
|
7
|
+
*
|
|
8
|
+
* - `topicMetrics` — one-shot aggregate snapshot of a model's tree
|
|
9
|
+
* (size, shape, overflow/deferral pressure, rejection total, last op).
|
|
10
|
+
* - `topicChangeLog` — newest-first audit trail (the append-only log is the
|
|
11
|
+
* replay/repair source).
|
|
12
|
+
* - `topicHealth` — structural invariant sweep; violations are human-readable
|
|
13
|
+
* strings, `warnCount` = violation count.
|
|
14
|
+
*
|
|
15
|
+
* ## Scope note
|
|
16
|
+
*
|
|
17
|
+
* `topic_change_log` has no `model_key` column (schema/topics.ts), so
|
|
18
|
+
* change-log queries scope through the model's topic keys via a subquery —
|
|
19
|
+
* the same pattern as `Store.deleteTree`.
|
|
20
|
+
*
|
|
21
|
+
* ## Complexity (current scale)
|
|
22
|
+
*
|
|
23
|
+
* - `topicMetrics`: one `topics` scan (`O(T)` rows, T = O(N/L)) + one
|
|
24
|
+
* `topic_growth_state` aggregate + one change-log head read.
|
|
25
|
+
* - `topicHealth`: one `topics` scan + ONE grouped `topic_memberships` count
|
|
26
|
+
* query (the current-scale equivalent of COUNT-per-topic; a production
|
|
27
|
+
* index would maintain per-topic counts instead).
|
|
28
|
+
*
|
|
29
|
+
* ## Determinism
|
|
30
|
+
*
|
|
31
|
+
* Ordering derives from persisted state only: `leafMemberCounts` is sorted
|
|
32
|
+
* ascending, change-log rows by `id` DESC (PK order, ties impossible). No
|
|
33
|
+
* wall-clock in any ordering decision.
|
|
34
|
+
*/
|
|
35
|
+
import { Effect } from "effect";
|
|
36
|
+
import { Service as DbBackend } from "../db-backend.ts";
|
|
37
|
+
import type { TopicConfig, TopicChangeLog } from "../schema/topics.ts";
|
|
38
|
+
import type { TopicError } from "./errors.ts";
|
|
39
|
+
import type { StoreError } from "../error.ts";
|
|
40
|
+
/** One-shot aggregate snapshot of a model's tree (see {@link topicMetrics}). */
|
|
41
|
+
export interface TopicMetrics {
|
|
42
|
+
readonly totalTopics: number;
|
|
43
|
+
readonly leaves: number;
|
|
44
|
+
readonly internal: number;
|
|
45
|
+
/** Maximum `depth` over all topic rows (0 = root only). */
|
|
46
|
+
readonly depth: number;
|
|
47
|
+
/** Member counts of every leaf, sorted ascending (regardless of status). */
|
|
48
|
+
readonly leafMemberCounts: ReadonlyArray<number>;
|
|
49
|
+
/** Leaves with `memberCount > config.maxLeafItems` (split-job pressure). */
|
|
50
|
+
readonly overflowCandidates: number;
|
|
51
|
+
/** Topics with status `split_deferred` (gate rejected, awaiting backstop). */
|
|
52
|
+
readonly deferredLeaves: number;
|
|
53
|
+
/** Sum of `split_rejected_count` over the model's growth-state rows. */
|
|
54
|
+
readonly splitRejectedTotal: number;
|
|
55
|
+
/** Newest change-log entry (by id), or null when the log is empty. */
|
|
56
|
+
readonly lastOperation: {
|
|
57
|
+
readonly operation: string;
|
|
58
|
+
readonly createdAt: number;
|
|
59
|
+
} | null;
|
|
60
|
+
}
|
|
61
|
+
/** Options for {@link topicChangeLog}. */
|
|
62
|
+
export interface TopicChangeLogOptions {
|
|
63
|
+
/** Only rows with this operation (e.g. `"split"`, `"create"`). */
|
|
64
|
+
readonly operation?: string;
|
|
65
|
+
/** Maximum rows returned, newest first (default 50). */
|
|
66
|
+
readonly limit?: number;
|
|
67
|
+
}
|
|
68
|
+
/** Structural health of a model's tree (see {@link topicHealth}). */
|
|
69
|
+
export interface TopicHealth {
|
|
70
|
+
/** Human-readable invariant violations; empty = healthy. */
|
|
71
|
+
readonly invariantViolations: ReadonlyArray<string>;
|
|
72
|
+
/** `invariantViolations.length`. */
|
|
73
|
+
readonly warnCount: number;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Aggregate metrics for one model's tree. Read-only; the caller decides what
|
|
77
|
+
* to act on (repair tooling, dashboards, overflow autoscaling).
|
|
78
|
+
*/
|
|
79
|
+
export declare const topicMetrics: (modelKey: string, config: TopicConfig) => Effect.Effect<TopicMetrics, TopicError | StoreError, DbBackend>;
|
|
80
|
+
/**
|
|
81
|
+
* Newest-first audit trail for a model's tree. Rows are ordered by `id` DESC
|
|
82
|
+
* (PK order — the append-only log's natural recency), limited to
|
|
83
|
+
* `opts.limit` (default 50), optionally filtered by `opts.operation`
|
|
84
|
+
* (exact match on the `operation` column).
|
|
85
|
+
*/
|
|
86
|
+
export declare const topicChangeLog: (modelKey: string, opts?: TopicChangeLogOptions) => Effect.Effect<ReadonlyArray<TopicChangeLog>, TopicError | StoreError, DbBackend>;
|
|
87
|
+
/**
|
|
88
|
+
* Structural invariant sweep for one model's tree. Reports every violation as
|
|
89
|
+
* a human-readable string; an empty `invariantViolations` means healthy.
|
|
90
|
+
*
|
|
91
|
+
* Checks:
|
|
92
|
+
* 1. Every leaf `memberCount <= maxLeafItems + slack`, where
|
|
93
|
+
* `slack = max(2, ceil(splitDeferredHardLimit / 2) − maxLeafItems)` — the
|
|
94
|
+
* same allowance the split acceptance gate grants a forced split's child.
|
|
95
|
+
* 2. Every internal topic has `childCount >= 2`. The reserved `__root__`
|
|
96
|
+
* anchor is exempt: it is seeded with `childCount 0` and routing/split
|
|
97
|
+
* never maintain it (the root's child set lives in `topic_relations`).
|
|
98
|
+
* 3. Leaf `memberCount` agrees with the actual `topic_memberships` row count
|
|
99
|
+
* (one grouped COUNT query — the current-scale stand-in for a
|
|
100
|
+
* maintained per-topic counter).
|
|
101
|
+
*/
|
|
102
|
+
export declare const topicHealth: (modelKey: string, config: TopicConfig) => Effect.Effect<TopicHealth, TopicError | StoreError, DbBackend>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic query routing: leaf selection for topic-scoped retrieval.
|
|
3
|
+
*
|
|
4
|
+
* Beam descent from `__root__`: at each level score the children of the
|
|
5
|
+
* current frontier, keep the top-`k` (`k = opts.beamWidth ?? config.beamWidth`,
|
|
6
|
+
* default 3), descend. Stops when the whole frontier is leaves. An empty
|
|
7
|
+
* result means the tree has no leaves (immature or corrupt) — the caller
|
|
8
|
+
* falls back to an unscoped search.
|
|
9
|
+
*
|
|
10
|
+
* ## Determinism
|
|
11
|
+
*
|
|
12
|
+
* - Topic rows are ordered by `topic_key` asc; children are sorted by
|
|
13
|
+
* `topic_key` asc; topic vectors come from `fetchTopicVectors` (ordered by
|
|
14
|
+
* `topic_key` asc).
|
|
15
|
+
* - `scoreChildren` breaks score ties to the smaller index, which IS the
|
|
16
|
+
* lexicographic tie-break (same argument as `routing.ts`).
|
|
17
|
+
* - No randomness, no wall-clock timestamps, no unordered iteration. Same DB
|
|
18
|
+
* state + same query ⇒ identical leaf keys.
|
|
19
|
+
*
|
|
20
|
+
* ## Complexity
|
|
21
|
+
*
|
|
22
|
+
* `O(D·B·C·d)` (D = maxDepth, B = beamWidth, C = children per node) plus one
|
|
23
|
+
* bounded read of the model's topics rows, relations and centroids. Final
|
|
24
|
+
* ranking still runs in libSQL (`vectorSearch` with `topic_key IN (...)`).
|
|
25
|
+
*/
|
|
26
|
+
import { Effect } from "effect";
|
|
27
|
+
import type { EmbeddingModelConfig } from "./internal/config/index.js";
|
|
28
|
+
import { Service as DbBackend } from "../db-backend.ts";
|
|
29
|
+
import type { TopicConfig } from "../schema/topics.ts";
|
|
30
|
+
import type { TopicError } from "./errors.ts";
|
|
31
|
+
import type { StoreError } from "../error.ts";
|
|
32
|
+
/** Options for {@link resolveTopics}. */
|
|
33
|
+
export interface ResolveTopicsOptions {
|
|
34
|
+
/** Number of children kept per level (default: `config.beamWidth`). */
|
|
35
|
+
readonly beamWidth?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the leaf topics a query should search: `readonly string[]` of
|
|
39
|
+
* `topic_key`s, ordered by score (descending; ties lexicographic). An empty
|
|
40
|
+
* array means the tree has no leaves — the caller falls back to an unscoped
|
|
41
|
+
* search.
|
|
42
|
+
*/
|
|
43
|
+
export declare const resolveTopics: (queryVector: ReadonlyArray<number>, model: EmbeddingModelConfig, config: TopicConfig, opts?: ResolveTopicsOptions) => Effect.Effect<ReadonlyArray<string>, TopicError | StoreError, DbBackend>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic topic-tree seeding + insert routing.
|
|
3
|
+
*
|
|
4
|
+
* ## Contracts
|
|
5
|
+
*
|
|
6
|
+
* - `ensureTopicTree` is an idempotent seed: creates the two reserved topics
|
|
7
|
+
* (`__root__` internal, `__unassigned_active__` leaf), their `parent_child`
|
|
8
|
+
* relation, growth-state rows and exactly one `create` change-log entry —
|
|
9
|
+
* all in one transaction, scoped by `model_key` (every model's
|
|
10
|
+
* tree has its own reserved rows — identity is the `(topic_key, model_key)`
|
|
11
|
+
* composite PK). Reserved keys sort before any `t_<hash>` key
|
|
12
|
+
* lexicographically (`_` = 0x5F < `t` = 0x74), which the descent relies on
|
|
13
|
+
* for stable tie-breaking.
|
|
14
|
+
* - `routeInsert` runs its Drizzle writes (membership insert, leaf CF, ancestor
|
|
15
|
+
* CF) in ONE transaction; the derived sum-vector upserts run immediately
|
|
16
|
+
* after commit (the backend is not transaction-aware — see below). It never
|
|
17
|
+
* writes change-log entries (only structural operations do).
|
|
18
|
+
* - Determinism: given the same DB state, the same `(memoryId, vector, model,
|
|
19
|
+
* config)` always lands in the same leaf. Children are sorted by
|
|
20
|
+
* `topic_key` and score ties break lexicographically (smaller key wins).
|
|
21
|
+
* No randomness,
|
|
22
|
+
* no insertion-order-dependent structure. Audit
|
|
23
|
+
* timestamps (`created_at`/`updated_at`) come from the injectable Effect
|
|
24
|
+
* Clock — they are observability data only and never influence routing.
|
|
25
|
+
*
|
|
26
|
+
* ## Transactions vs the backend (documented limitation)
|
|
27
|
+
*
|
|
28
|
+
* `upsertTopicVector` / `fetchTopicVectors` are DbBackend raw-SQL calls on the
|
|
29
|
+
* client connection, NOT transaction-aware. Drizzle's libsql transaction runs
|
|
30
|
+
* on a **separate connection** (`client.transaction()`), so calling them
|
|
31
|
+
* inside the tx callback fails with `SQLITE_BUSY`. The code therefore
|
|
32
|
+
* keeps every Drizzle write (membership + `topics` CF rows) in the single
|
|
33
|
+
* transaction and runs the vector-table upserts immediately AFTER commit.
|
|
34
|
+
* Consequence: the derived sum vectors are eventually consistent with the
|
|
35
|
+
* strictly-consistent membership — a crash between commit and upsert
|
|
36
|
+
* leaves a stale centroid, never an orphaned membership. Single-writer local
|
|
37
|
+
* file DB, so the pre-tx read set is stable; if the backend grows
|
|
38
|
+
* transaction-aware vector methods, move the upserts onto the tx.
|
|
39
|
+
*/
|
|
40
|
+
import { Effect } from "effect";
|
|
41
|
+
import type { EmbeddingModelConfig } from "./internal/config/index.js";
|
|
42
|
+
import { Service as DbBackend } from "../db-backend.ts";
|
|
43
|
+
import type { TopicConfig } from "../schema/topics.ts";
|
|
44
|
+
import type { TopicError } from "./errors.ts";
|
|
45
|
+
import type { StoreError } from "../error.ts";
|
|
46
|
+
/** Reserved tree root — internal router, depth 0. */
|
|
47
|
+
export declare const ROOT_TOPIC_KEY = "__root__";
|
|
48
|
+
/** Reserved overflow/seed leaf under the root — depth 1. */
|
|
49
|
+
export declare const UNASSIGNED_ACTIVE_TOPIC_KEY = "__unassigned_active__";
|
|
50
|
+
/**
|
|
51
|
+
* Idempotent tree seed. If the model's `__root__` exists the tree is already
|
|
52
|
+
* seeded and this is a no-op (the existence check runs INSIDE the transaction
|
|
53
|
+
* and is scoped by `model_key` — (multi-model) the reserved keys are the same
|
|
54
|
+
* strings in every model's tree, and the `(topic_key, model_key)` composite PK
|
|
55
|
+
* is what separates them; two concurrent seeds of the same model cannot
|
|
56
|
+
* double-insert). Otherwise one transaction creates:
|
|
57
|
+
* `__root__` (internal, depth 0), `__unassigned_active__` (leaf, depth 1,
|
|
58
|
+
* `parent_child` under root), growth-state rows for both, and one `create`
|
|
59
|
+
* change-log entry.
|
|
60
|
+
*
|
|
61
|
+
* Also ensures the per-model topic vector table exists (idempotent
|
|
62
|
+
* `CREATE TABLE IF NOT EXISTS`) — `routeInsert` upserts into it, so the seed
|
|
63
|
+
* is the natural lifecycle point.
|
|
64
|
+
*/
|
|
65
|
+
export declare const ensureTopicTree: (model: EmbeddingModelConfig, config: TopicConfig) => Effect.Effect<{
|
|
66
|
+
rootKey: string;
|
|
67
|
+
unassignedKey: string;
|
|
68
|
+
}, TopicError | StoreError, DbBackend>;
|
|
69
|
+
/**
|
|
70
|
+
* Route one memory (its embedding `vector`) into the model's tree and update
|
|
71
|
+
* the affected CF-triplets:
|
|
72
|
+
*
|
|
73
|
+
* 1. Route: greedy descent from `__root__` through the best child centroid,
|
|
74
|
+
* capped at `maxDepth` (lexicographic tie-break).
|
|
75
|
+
* 2. ONE transaction: insert the `topic_memberships` row, update the leaf CF
|
|
76
|
+
* (`memberCount + 1`, `sumSquares += x·x`, sum vector `+= x` — O(1) exact
|
|
77
|
+
* via `cfInsert`), and walk the ancestors (`memberCount + 1`, sum vector
|
|
78
|
+
* `+= x` per level — exact O(depth · d)).
|
|
79
|
+
* 3. After commit: write the derived sum vectors to the per-model topic vector
|
|
80
|
+
* table (backend upserts — see module docs).
|
|
81
|
+
* 4. `overflow = memberCount > maxLeafItems` after the update (the caller
|
|
82
|
+
* decides whether to enqueue a structural job).
|
|
83
|
+
*
|
|
84
|
+
* Deterministic given the same DB state (see module docs). Does NOT write
|
|
85
|
+
* change-log entries — only structural operations do.
|
|
86
|
+
*/
|
|
87
|
+
export declare const routeInsert: (memoryId: string, vector: ReadonlyArray<number>, model: EmbeddingModelConfig, config: TopicConfig) => Effect.Effect<{
|
|
88
|
+
topicKey: string;
|
|
89
|
+
overflow: boolean;
|
|
90
|
+
}, TopicError | StoreError, DbBackend>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared topic-vector-table helpers for the structural jobs (split, merge,
|
|
3
|
+
* borrow, rebalance). The per-model `topic_vec_<dims>_<model>` tables are
|
|
4
|
+
* dynamic (not Drizzle tables), so every writer goes through this raw-SQL
|
|
5
|
+
* helper — one canonical place for the table name + conversion function.
|
|
6
|
+
*/
|
|
7
|
+
import type { EmbeddingModelConfig } from "./internal/config/index.js";
|
|
8
|
+
import { type SQLWrapper } from "drizzle-orm";
|
|
9
|
+
/** Per-model topic vector table name (mirrors libsql-backend.ts — canonical). */
|
|
10
|
+
export declare const topicVectorTableName: (model: EmbeddingModelConfig) => string;
|
|
11
|
+
/** vectorType → libSQL conversion function for the sum-vector column. */
|
|
12
|
+
export declare const VECTOR_CONVERT_FNS: Readonly<Record<string, string>>;
|
|
13
|
+
/** Anything with a `.run(sql)` — a Drizzle tx or the db handle. */
|
|
14
|
+
export interface SqlRunner {
|
|
15
|
+
readonly run: (query: string | SQLWrapper<unknown>) => unknown;
|
|
16
|
+
}
|
|
17
|
+
/** Delete one topic's sum-vector row (merge absorbs the sibling's row). */
|
|
18
|
+
export declare const deleteTopicVectorRow: (runner: SqlRunner, model: EmbeddingModelConfig, topicKey: string) => Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Upsert one topic's sum vector. `ls` is the CF-triplet LS (sum of member
|
|
21
|
+
* vectors) as a plain Float32Array. Works inside a transaction (structural
|
|
22
|
+
* ops) or directly on the db handle (repair paths).
|
|
23
|
+
*/
|
|
24
|
+
export declare const writeTopicVector: (runner: SqlRunner, model: EmbeddingModelConfig, topicKey: string, ls: Float32Array) => Promise<void>;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, deterministic topic-tree algorithms.
|
|
3
|
+
*
|
|
4
|
+
* All functions in this module are synchronous, side-effect free, and never
|
|
5
|
+
* mutate their inputs. They operate on plain `Float32Array` vectors.
|
|
6
|
+
*
|
|
7
|
+
* ## Invariant: vectors are L2-normalized
|
|
8
|
+
*
|
|
9
|
+
* The embedder normalizes every vector (`transformers.js`, `normalize: true`),
|
|
10
|
+
* so for every stored vector `||x|| = 1` (or the zero vector, in degenerate
|
|
11
|
+
* cases). Consequently **cosine similarity equals the dot product**, and all
|
|
12
|
+
* similarity comparisons in this module are plain dot products. A zero vector
|
|
13
|
+
* behaves as a "neutral" item: its dot product with anything is `0`.
|
|
14
|
+
*
|
|
15
|
+
* ## Determinism contract
|
|
16
|
+
*
|
|
17
|
+
* - No randomness, no wall-clock timestamps, no insertion-order-dependent
|
|
18
|
+
* structure.
|
|
19
|
+
* - Ties always break to the SMALLER index (farthest-pair candidate, group
|
|
20
|
+
* assignment, child ranking).
|
|
21
|
+
* - Same input + same config ⇒ bit-identical output.
|
|
22
|
+
*
|
|
23
|
+
* ## Complexity
|
|
24
|
+
*
|
|
25
|
+
* `n` = vectors in a leaf (bounded by `maxLeafItems` / split-deferred hard
|
|
26
|
+
* limit), `d` = embedding dimensions. Split machinery is `O(passes · n · d)`
|
|
27
|
+
* with `n ≤ 512`.
|
|
28
|
+
*/
|
|
29
|
+
import type { TopicConfig } from "../schema/topics.ts";
|
|
30
|
+
/**
|
|
31
|
+
* BIRCH CF-triplet: sufficient statistics of a vector set.
|
|
32
|
+
* `count` = N, `ls` = sum vector, `ss` = sum of squared norms.
|
|
33
|
+
* Supports O(1) exact insert/remove and closed-form centroid/radius — no
|
|
34
|
+
* vector scans for aggregates.
|
|
35
|
+
*/
|
|
36
|
+
export interface CfTriplet {
|
|
37
|
+
readonly count: number;
|
|
38
|
+
readonly ls: Float32Array;
|
|
39
|
+
readonly ss: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build the CF-triplet of a vector set. All vectors must share one length;
|
|
43
|
+
* an empty input yields a zero-dimension triplet (`count = 0`).
|
|
44
|
+
*/
|
|
45
|
+
export declare const cfFromVectors: (vectors: readonly Float32Array[]) => CfTriplet;
|
|
46
|
+
/**
|
|
47
|
+
* O(1) exact insert of vector `x` into a CF-triplet. Returns a new triplet;
|
|
48
|
+
* neither input is mutated.
|
|
49
|
+
*/
|
|
50
|
+
export declare const cfInsert: (cf: CfTriplet, x: Float32Array) => CfTriplet;
|
|
51
|
+
/**
|
|
52
|
+
* O(1) exact removal of vector `x` from a CF-triplet. `count` clamps at 0 and
|
|
53
|
+
* `ss` clamps at 0 (float subtraction can round slightly below). Returns a
|
|
54
|
+
* new triplet; neither input is mutated.
|
|
55
|
+
*/
|
|
56
|
+
export declare const cfRemove: (cf: CfTriplet, x: Float32Array) => CfTriplet;
|
|
57
|
+
/**
|
|
58
|
+
* Centroid (mean vector) of a CF-triplet: `ls / count`. An empty triplet
|
|
59
|
+
* (`count = 0`) yields the zero vector of the same dimension.
|
|
60
|
+
*/
|
|
61
|
+
export declare const centroidOf: (cf: CfTriplet) => Float32Array;
|
|
62
|
+
/**
|
|
63
|
+
* RMS radius of a CF-triplet: `sqrt(max(ss/count - |mean|^2, 0))` — the
|
|
64
|
+
* exact root-mean-square deviation of members from the centroid, computed
|
|
65
|
+
* from the CF alone (no vector scan). Empty triplet ⇒ `0`.
|
|
66
|
+
*/
|
|
67
|
+
export declare const radiusOf: (cf: CfTriplet) => number;
|
|
68
|
+
/**
|
|
69
|
+
* BIRCH-style weighted radius of a CF-triplet: `ss - |ls|^2 / count`, the
|
|
70
|
+
* sum of squared deviations from the centroid, exact from the CF alone.
|
|
71
|
+
* By the variance decomposition this equals the parent's weighted radius
|
|
72
|
+
* minus the between-group term for any two-group partition — the quantity
|
|
73
|
+
* Lloyd refinement monotonically decreases (exact arithmetic; float32
|
|
74
|
+
* accumulation noise is < 1e-3 relative). Empty triplet ⇒ `0`.
|
|
75
|
+
*/
|
|
76
|
+
export declare const weightedRadiusOf: (cf: CfTriplet) => number;
|
|
77
|
+
/**
|
|
78
|
+
* Content-canonical permutation of `vectors`: indices sorted by
|
|
79
|
+
* lexicographic coordinate order (stable — equal vectors keep input order).
|
|
80
|
+
* `sorted[i] = vectors[order[i]!]`. The whole split pipeline runs on the
|
|
81
|
+
* canonical order so its output is a function of the vector SET, not of the
|
|
82
|
+
* caller's array order (random UUID-ordered memberships must not change the
|
|
83
|
+
* tree shape — the benchmark flake root cause).
|
|
84
|
+
*/
|
|
85
|
+
export declare const canonicalOrder: (vectors: readonly Float32Array[]) => readonly number[];
|
|
86
|
+
/**
|
|
87
|
+
* Deterministic farthest-first seed pair: `a = 0` (first vector of the
|
|
88
|
+
* CANONICAL order — callers must sort via {@link canonicalOrder} first),
|
|
89
|
+
* then `b` = the vector with the lowest dot product against `a` (farthest
|
|
90
|
+
* under the normalized-vector invariant). Ties break to the smaller index.
|
|
91
|
+
* For fewer than 2 vectors returns `{ a: 0, b: 0 }` (degenerate — callers
|
|
92
|
+
* guard on counts before splitting). Never mutates input.
|
|
93
|
+
*/
|
|
94
|
+
export declare const farthestPair: (vectors: readonly Float32Array[]) => {
|
|
95
|
+
a: number;
|
|
96
|
+
b: number;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Assign every vector to group 0 or 1 by higher dot product against the
|
|
100
|
+
* seed vectors at `seedA` / `seedB`; ties go to group 0 (smaller index).
|
|
101
|
+
* Returns a fresh `Uint8Array` (`0` = closer to `seedA`, `1` = closer to
|
|
102
|
+
* `seedB`). Never mutates inputs.
|
|
103
|
+
*/
|
|
104
|
+
export declare const assignNearest: (vectors: readonly Float32Array[], seedA: number, seedB: number) => Uint8Array;
|
|
105
|
+
/**
|
|
106
|
+
* Deterministic Lloyd refinement: recompute each group's centroid, reassign
|
|
107
|
+
* every vector to the group with the higher dot product (tie ⇒ smaller group
|
|
108
|
+
* index, i.e. 0), repeat for `passes` iterations. Stops early at a fixpoint —
|
|
109
|
+
* further passes are no-ops, so the result is identical either way. Returns
|
|
110
|
+
* the final groups plus both group CF-triplets.
|
|
111
|
+
*
|
|
112
|
+
* Monotone: the sum of weighted radii never increases in exact arithmetic.
|
|
113
|
+
* Comparisons use the float64 division of the float32-accumulated sum
|
|
114
|
+
* `ls / count` (not the float32-rounded {@link centroidOf}) so that each
|
|
115
|
+
* reassignment is a true SSE minimization — the classic Lloyd chain
|
|
116
|
+
* `WR(new) ≤ WR(new, μ_old) ≤ WR(old)` holds in float64. The contract-mandated
|
|
117
|
+
* float32 `ls` accumulation perturbs the *measured* WR by < 1e-3 relative
|
|
118
|
+
* (empirically ≤ 5e-4 over 2000 seeds).
|
|
119
|
+
*
|
|
120
|
+
* Never mutates inputs.
|
|
121
|
+
*/
|
|
122
|
+
export declare const lloydRefine: (vectors: readonly Float32Array[], groups: Uint8Array, passes: number) => {
|
|
123
|
+
groups: Uint8Array;
|
|
124
|
+
leftCf: CfTriplet;
|
|
125
|
+
rightCf: CfTriplet;
|
|
126
|
+
};
|
|
127
|
+
/** Outcome of {@link splitPlan} — accepted splits plus the acceptance gate diagnostics. */
|
|
128
|
+
export interface SplitPlanResult {
|
|
129
|
+
readonly accepted: boolean;
|
|
130
|
+
readonly reason: "ok" | "unbalanced" | "no-improvement";
|
|
131
|
+
readonly groups: Uint8Array;
|
|
132
|
+
readonly leftCount: number;
|
|
133
|
+
readonly rightCount: number;
|
|
134
|
+
readonly leftWeightedRadius: number;
|
|
135
|
+
readonly rightWeightedRadius: number;
|
|
136
|
+
readonly parentWeightedRadius: number;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Deterministic 2-way split plan for one leaf: content-canonical ordering →
|
|
140
|
+
* farthest-pair seeds → nearest-seed assignment → Lloyd refinement
|
|
141
|
+
* (`config.lloydPasses` passes). Accepted iff both child counts reach
|
|
142
|
+
* `config.minLeafItems` AND the summed child weighted radii are strictly
|
|
143
|
+
* below the parent's (a non-degenerate split strictly reduces weighted
|
|
144
|
+
* radius by the between-group term `(n₁n₂/n)·|μ₁−μ₂|²`; equality —
|
|
145
|
+
* "no-improvement" — means the centroids coincide). Reason precedence:
|
|
146
|
+
* `"unbalanced"` (count gate) before `"no-improvement"` (radius gate).
|
|
147
|
+
*
|
|
148
|
+
* ## Determinism (v3)
|
|
149
|
+
*
|
|
150
|
+
* The pipeline first reorders the input via {@link canonicalOrder}, so the
|
|
151
|
+
* returned plan is a function of the vector SET only — never of the
|
|
152
|
+
* caller's array order. `groups` is un-permuted back to the CALLER's index
|
|
153
|
+
* space before returning (index `i` corresponds to `vectors[i]`), so
|
|
154
|
+
* callers map group assignments straight onto their own member ids.
|
|
155
|
+
*
|
|
156
|
+
* Remaining order-dependence: bit-identical vectors keep their input
|
|
157
|
+
* relative order (stable sort) and always score equally, so they land in
|
|
158
|
+
* the same group; only the float32 accumulation inside `cfOfGroup` can
|
|
159
|
+
* round differently for them (≤ 1 ulp on `ls`) — it cannot flip a distinct
|
|
160
|
+
* vector's assignment unless that vector is itself within 1 ulp of a tie.
|
|
161
|
+
*
|
|
162
|
+
* Never mutates inputs.
|
|
163
|
+
*/
|
|
164
|
+
export declare const splitPlan: (vectors: readonly Float32Array[], config: TopicConfig) => SplitPlanResult;
|
|
165
|
+
/**
|
|
166
|
+
* Score child centroids against a query vector: dot products, sorted
|
|
167
|
+
* descending; ties break to the smaller index. Returns a fresh array of
|
|
168
|
+
* `{ index, score }` pairs (index = position in `centroids`). Never mutates
|
|
169
|
+
* inputs.
|
|
170
|
+
*/
|
|
171
|
+
export declare const scoreChildren: (centroids: readonly Float32Array[], query: Float32Array) => Array<{
|
|
172
|
+
index: number;
|
|
173
|
+
score: number;
|
|
174
|
+
}>;
|
|
175
|
+
/**
|
|
176
|
+
* Validate a `TopicConfig` against the structural invariants of the tree.
|
|
177
|
+
* Returns an array of violation strings (empty when valid). Warnings — such
|
|
178
|
+
* as `minLeafItems * 2 > maxLeafItems`, which makes splits unsatisfiable at
|
|
179
|
+
* a full leaf — are included so callers can log them without failing.
|
|
180
|
+
*/
|
|
181
|
+
export declare const validateConfig: (config: TopicConfig) => ReadonlyArray<string>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { GrammarProvisionError } from "@dimple/shared/errors";
|
|
3
|
+
import { Service as TreeSitterRegistry } from "./wasm-registry";
|
|
4
|
+
import { Service as WasmDownloader } from "./wasm-downloader";
|
|
5
|
+
import { Service as WasmCache } from "./wasm-cache";
|
|
6
|
+
export interface Interface {
|
|
7
|
+
readonly ensure: (lang: string) => Effect.Effect<string, GrammarProvisionError>;
|
|
8
|
+
}
|
|
9
|
+
declare const Service_base: Context.ServiceClass<Service, "@dimple/wasm/GrammarStore", Interface>;
|
|
10
|
+
export declare class Service extends Service_base {
|
|
11
|
+
}
|
|
12
|
+
export declare const layer: Layer.Layer<Service, never, TreeSitterRegistry | WasmDownloader | WasmCache>;
|
|
13
|
+
export declare const allLive: Layer.Layer<TreeSitterRegistry | WasmDownloader | WasmCache | Service, never, never>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Service as TreeSitterRegistry } from "./wasm-registry";
|
|
2
|
+
export type { GrammarMetaData } from "./wasm-registry";
|
|
3
|
+
export { Service as WasmDownloader } from "./wasm-downloader";
|
|
4
|
+
export { Service as WasmCache, layer as wasmCacheLayer } from "./wasm-cache";
|
|
5
|
+
export { Service as GrammarStore, layer as grammarStoreLayer, allLive as GrammarStoreAllLive, } from "./grammar-store";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { WasmCacheError } from "@dimple/shared/errors";
|
|
3
|
+
/**
|
|
4
|
+
* Grammar WASM cache — downloads are staged to a temp file and renamed
|
|
5
|
+
* into place (an interrupted download never leaves a corrupt parser).
|
|
6
|
+
* Plain `node:fs` (NOT @effect/platform-bun): the bundled SDK runs on
|
|
7
|
+
* Node too (the CLI's shebang spawns node), so Bun-specific filesystem
|
|
8
|
+
* layers are off the table.
|
|
9
|
+
*/
|
|
10
|
+
export interface Interface {
|
|
11
|
+
readonly ensure: (lang: string, version: string, download: Effect.Effect<Uint8Array>) => Effect.Effect<string, WasmCacheError>;
|
|
12
|
+
}
|
|
13
|
+
declare const Service_base: Context.ServiceClass<Service, "@dimple/wasm/WasmCache", Interface>;
|
|
14
|
+
export declare class Service extends Service_base {
|
|
15
|
+
}
|
|
16
|
+
export declare const layer: Layer.Layer<Service, never, never>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { WasmDownloadError } from "@dimple/shared/errors";
|
|
3
|
+
export interface Interface {
|
|
4
|
+
readonly download: (url: string) => Effect.Effect<Uint8Array, WasmDownloadError>;
|
|
5
|
+
}
|
|
6
|
+
declare const Service_base: Context.ServiceClass<Service, "@dimple/wasm/WasmDownloader", Interface>;
|
|
7
|
+
export declare class Service extends Service_base {
|
|
8
|
+
static readonly layer: Layer.Layer<Service, never, never>;
|
|
9
|
+
}
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Schema } from "effect";
|
|
2
|
+
import { RegistryError } from "@dimple/shared/errors";
|
|
3
|
+
declare const GrammarMetaDataSchema: Schema.Struct<{
|
|
4
|
+
readonly lang: Schema.String;
|
|
5
|
+
readonly version: Schema.String;
|
|
6
|
+
readonly url: Schema.String;
|
|
7
|
+
}>;
|
|
8
|
+
export type GrammarMetaData = typeof GrammarMetaDataSchema.Type;
|
|
9
|
+
export interface Interface {
|
|
10
|
+
readonly resolve: (lang: string) => Effect.Effect<GrammarMetaData, RegistryError>;
|
|
11
|
+
}
|
|
12
|
+
declare const Service_base: Context.ServiceClass<Service, "@dimple/wasm/TreeSitterRegistry", Interface>;
|
|
13
|
+
export declare class Service extends Service_base {
|
|
14
|
+
static readonly layer: Layer.Layer<Service, never, never>;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job runtime configuration — the `jobs` section of `dimple.jsonc`.
|
|
3
|
+
*
|
|
4
|
+
* All fields optional; `resolveJobsConfig` fills the documented defaults.
|
|
5
|
+
* Consumed by the deployment wiring (executor mode selection, worker
|
|
6
|
+
* concurrency, queue lease/attempt tuning) — the facade itself reads its
|
|
7
|
+
* options from the layer composition, not from this schema.
|
|
8
|
+
*/
|
|
9
|
+
import { Schema } from "effect";
|
|
10
|
+
export declare const JobsConfig: Schema.Struct<{
|
|
11
|
+
/** libSQL URL for the dedicated jobs database. */
|
|
12
|
+
readonly dbUrl: Schema.optional<Schema.String>;
|
|
13
|
+
/** `background` (worker layers) | `inline` (submit-scope worker) | `external` (cron drain).
|
|
14
|
+
* RESERVED: the core composition currently installs background workers
|
|
15
|
+
* only (the config package parses it but nothing switches on it yet). */
|
|
16
|
+
readonly execution: Schema.optional<Schema.Literals<readonly ["background", "inline", "external"]>>;
|
|
17
|
+
/** Worker concurrency per queue. */
|
|
18
|
+
readonly concurrency: Schema.optional<Schema.Number>;
|
|
19
|
+
/** Queue item lease duration in ms (→ `PersistedQueue` `lockExpiration`).
|
|
20
|
+
* RESERVED: not yet wired to the executor. */
|
|
21
|
+
readonly leaseTimeoutMs: Schema.optional<Schema.Number>;
|
|
22
|
+
/** Max attempts per queue item before it is dropped (→ `take maxAttempts`). */
|
|
23
|
+
readonly maxAttempts: Schema.optional<Schema.refine<number, Schema.Number>>;
|
|
24
|
+
/** External-drain poll window hint in ms. RESERVED: not yet wired. */
|
|
25
|
+
readonly pollIntervalMs: Schema.optional<Schema.Number>;
|
|
26
|
+
}>;
|
|
27
|
+
export interface JobsConfig extends Schema.Schema.Type<typeof JobsConfig> {
|
|
28
|
+
}
|
|
29
|
+
/** Documented defaults — the source of truth for `resolveJobsConfig`. */
|
|
30
|
+
export declare const JobsConfigDefaults: {
|
|
31
|
+
dbUrl: string;
|
|
32
|
+
execution: "background";
|
|
33
|
+
concurrency: number;
|
|
34
|
+
leaseTimeoutMs: number;
|
|
35
|
+
maxAttempts: number;
|
|
36
|
+
pollIntervalMs: number;
|
|
37
|
+
};
|
|
38
|
+
/** Fills every optional field with its documented default. */
|
|
39
|
+
export declare const resolveJobsConfig: (config: JobsConfig) => Required<JobsConfig>;
|