@ponraaj/dimple-sdk 0.0.0-alpha.13 → 0.0.0-alpha.14

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.
@@ -5,7 +5,7 @@ import { EmbeddingError, type EmbeddingModel } from "../embedder/index.js";
5
5
  import type { LogConfig, Logging } from "../logger/index.js";
6
6
  import { Store, graph, type TopicConfig } from "../store/index.js";
7
7
  import { HybridRetrieval } from "../retriever/index.js";
8
- import { JobRuntime, JobRegistry, type Handler, type JobDefinition } from "../workflow/index.js";
8
+ import { JobRuntime, JobRegistry, QueueStats, type Handler, type JobDefinition } from "../workflow/index.js";
9
9
  /** Topic-tree config (the store's schema, defaults decoded by the layer). */
10
10
  export type { TopicConfig } from "../store/index.js";
11
11
  /** Graph config (the store's schema — `graph.GraphConfig`). */
@@ -71,6 +71,9 @@ export interface Interface {
71
71
  readonly store: Store["Service"];
72
72
  readonly hybrid: HybridRetrieval["Service"];
73
73
  readonly runtime: JobRuntime["Service"];
74
+ /** Pending durable-queue elements per queue — drain visibility for the
75
+ * status surfaces (`dimple health`, `dimple://health`). */
76
+ readonly queueStats: QueueStats["Service"];
74
77
  readonly registry: JobRegistry["Service"];
75
78
  readonly models: ReadonlyMap<string, EmbeddingModelConfig>;
76
79
  readonly defaultModel: EmbeddingModelConfig;
@@ -2,7 +2,7 @@ import { Layer } from "effect";
2
2
  import { Store, DbBackend } from "../store/index.js";
3
3
  import { EmbeddingError, EmbeddingModelRegistry } from "../embedder/index.js";
4
4
  import { HybridRetrieval } from "../retriever/index.js";
5
- import { JobRuntime, JobRegistry } from "../workflow/index.js";
5
+ import { JobRuntime, JobRegistry, QueueStats } from "../workflow/index.js";
6
6
  import { Logging } from "../logger/index.js";
7
7
  import { Service as ConfigService } from "../config/index.js";
8
8
  import type { CoreOptions } from "./core.ts";
@@ -17,7 +17,7 @@ import { Service } from "./core.ts";
17
17
  * service (it runs fibers).
18
18
  */
19
19
  export type CoreGraphServices = Layer.Success<ReturnType<typeof layer>>;
20
- export declare const layer: (options: CoreOptions) => Layer.Layer<import("effect/persistence/PersistedQueue").PersistedQueueFactory | import("effect/persistence/Persistence").Persistence | Logging | DbBackend | JobRuntime | JobRegistry | Store | EmbeddingModelRegistry | HybridRetrieval | Service | import("effect/workflow/WorkflowEngine").WorkflowEngine, CoreConfigError | EmbeddingError | import("../retriever/index.js").HybridError | import("../workflow/index.js").RegistryError | import("effect/sql/SqlError").SqlError | import("../store/index.js").StoreError, never>;
20
+ export declare const layer: (options: CoreOptions) => Layer.Layer<import("effect/persistence/PersistedQueue").PersistedQueueFactory | import("effect/persistence/Persistence").Persistence | Logging | DbBackend | QueueStats | JobRuntime | JobRegistry | Store | EmbeddingModelRegistry | HybridRetrieval | Service | import("effect/workflow/WorkflowEngine").WorkflowEngine, CoreConfigError | EmbeddingError | import("../retriever/index.js").HybridError | import("../workflow/index.js").RegistryError | import("effect/sql/SqlError").SqlError | import("../store/index.js").StoreError, never>;
21
21
  /**
22
22
  * Config-driven variant — the `dimple.jsonc` path (the SDK's
23
23
  * `makeDimple({ config })`): reads the resolved `DimpleConfig` from
@@ -27,4 +27,4 @@ export declare const layer: (options: CoreOptions) => Layer.Layer<import("effect
27
27
  */
28
28
  export declare const layerConfig: (options?: {
29
29
  readonly migrationFolder?: string;
30
- }) => Layer.Layer<import("effect/persistence/PersistedQueue").PersistedQueueFactory | import("effect/persistence/Persistence").Persistence | Logging | DbBackend | JobRuntime | JobRegistry | Store | EmbeddingModelRegistry | HybridRetrieval | Service | import("effect/workflow/WorkflowEngine").WorkflowEngine, CoreConfigError | EmbeddingError | import("../retriever/index.js").HybridError | import("../workflow/index.js").RegistryError | import("effect/sql/SqlError").SqlError | import("../store/index.js").StoreError, ConfigService>;
30
+ }) => Layer.Layer<import("effect/persistence/PersistedQueue").PersistedQueueFactory | import("effect/persistence/Persistence").Persistence | Logging | DbBackend | QueueStats | JobRuntime | JobRegistry | Store | EmbeddingModelRegistry | HybridRetrieval | Service | import("effect/workflow/WorkflowEngine").WorkflowEngine, CoreConfigError | EmbeddingError | import("../retriever/index.js").HybridError | import("../workflow/index.js").RegistryError | import("effect/sql/SqlError").SqlError | import("../store/index.js").StoreError, ConfigService>;
@@ -102,7 +102,7 @@ export declare const routeInsert: (memoryId: string, vector: ReadonlyArray<numbe
102
102
  * so the descents are bit-identical to sequential routeInsert calls
103
103
  * against the DB (same reads, same writes, same order).
104
104
  * 3. Applies ALL membership inserts + topic CF updates in ONE
105
- * transaction (per-topic deltas accumulated in memory).
105
+ * transaction (per-topic FINAL states accumulated in memory).
106
106
  * 4. Writes the derived sum vectors in ONE batched upsert (backend
107
107
  * `upsertTopicVectors`), still after commit (backend not
108
108
  * transaction-aware — see module docs).
@@ -31,6 +31,7 @@ import { Layer } from "effect";
31
31
  import { WorkflowEngine } from "effect/workflow";
32
32
  import { Persistence as PersistenceNamespace, PersistedQueue } from "effect/persistence";
33
33
  import { SqlError as SqlErrorNamespace } from "effect/sql";
34
+ import { Service as QueueStatsService } from "./stats.ts";
34
35
  type SqlError = SqlErrorNamespace.SqlError;
35
36
  /**
36
37
  * Durable WorkflowEngine layer.
@@ -50,7 +51,7 @@ export declare const layerDurable: Layer.Layer<WorkflowEngine.WorkflowEngine, ne
50
51
  */
51
52
  export declare const libsqlStack: (options: {
52
53
  readonly url: string;
53
- }) => Layer.Layer<PersistedQueue.PersistedQueueFactory | PersistenceNamespace.Persistence, SqlErrorNamespace.SqlError, never>;
54
+ }) => Layer.Layer<PersistedQueue.PersistedQueueFactory | PersistenceNamespace.Persistence | QueueStatsService, SqlErrorNamespace.SqlError, never>;
54
55
  /**
55
56
  * Convenience layer: durable engine + SQL persistence + resume queue + libSQL
56
57
  * client, all sharing one libSQL instance. Surfaces `SqlError` from the
@@ -71,7 +72,7 @@ export declare const layerDurableLibsql: (options: {
71
72
  */
72
73
  export declare const libsqlStackConfigured: (options: {
73
74
  readonly url: string;
74
- }) => import("../core/index.js").LayerProvider<PersistedQueue.PersistedQueueFactory | PersistenceNamespace.Persistence, SqlErrorNamespace.SqlError, undefined>;
75
+ }) => import("../core/index.js").LayerProvider<PersistedQueue.PersistedQueueFactory | PersistenceNamespace.Persistence | QueueStatsService, SqlErrorNamespace.SqlError, undefined>;
75
76
  export declare const layerDurableLibsqlConfigured: (options: {
76
77
  readonly url: string;
77
78
  }) => import("../core/index.js").LayerProvider<WorkflowEngine.WorkflowEngine, SqlErrorNamespace.SqlError, undefined>;
@@ -6,6 +6,7 @@
6
6
  export { JobDefinition, Envelope, TopicSplit, MemoryEmbed, MemoryEmbedBatch, TopicMerge, TopicRebalance, ConceptCluster, MemoryDream, GraphRepair, AuditWrite, type AuditRow, queues, type EnvelopeSchema, } from "./queue.ts";
7
7
  export { Service as JobRuntime, layer as jobRuntimeLayer, configured as jobRuntimeConfigured, node as jobRuntimeNode, type Interface as JobRuntimeInterface, type JobStatus, } from "./runtime.ts";
8
8
  export { layerDurable, layerDurableLibsql, libsqlStackConfigured, layerDurableLibsqlConfigured, } from "./engine.ts";
9
+ export { Service as QueueStats, layer as queueStatsLayer, type Interface as QueueStatsInterface, type QueueStat, } from "./stats.ts";
9
10
  export { Service as JobRegistry, layer as jobRegistryLayer, configured as jobRegistryConfigured, node as jobRegistryNode, JobFailure, type Handler, type JobContext, } from "./registry.ts";
10
11
  export { workerLayer, configured as workersConfigured, inline, processQueues } from "./executor.ts";
11
12
  export { JobsConfig, JobsConfigDefaults, resolveJobsConfig } from "./config.ts";
@@ -56,6 +56,7 @@ import { PersistedQueue, Persistence as PersistenceNamespace } from "effect/pers
56
56
  import { SqlError as SqlErrorNamespace } from "effect/sql";
57
57
  import { type JobDefinition } from "./queue.ts";
58
58
  import { type JobsError } from "./errors.ts";
59
+ import { Service as QueueStatsService } from "./stats.ts";
59
60
  type SqlError = SqlErrorNamespace.SqlError;
60
61
  /**
61
62
  * Lifecycle of a job from the caller's perspective.
@@ -157,7 +158,7 @@ export declare const layer: (defs: readonly JobDefinition.Any[]) => Layer.Layer<
157
158
  */
158
159
  export declare const layerLibsql: (defs: readonly JobDefinition.Any[], options: {
159
160
  readonly url: string;
160
- }) => Layer.Layer<Service | WorkflowEngine.WorkflowEngine | PersistenceNamespace.Persistence | PersistedQueue.PersistedQueueFactory, SqlError>;
161
+ }) => Layer.Layer<Service | WorkflowEngine.WorkflowEngine | PersistenceNamespace.Persistence | PersistedQueue.PersistedQueueFactory | QueueStatsService, SqlError>;
161
162
  /**
162
163
  * OpenCode-style node declaration for {@link layerLibsql}.
163
164
  *
@@ -167,7 +168,7 @@ export declare const layerLibsql: (defs: readonly JobDefinition.Any[], options:
167
168
  */
168
169
  export declare const configured: (defs: readonly JobDefinition.Any[], options: {
169
170
  readonly url: string;
170
- }) => import("../core/index.js").LayerProvider<PersistedQueue.PersistedQueueFactory | PersistenceNamespace.Persistence | Service | WorkflowEngine.WorkflowEngine, SqlErrorNamespace.SqlError, undefined>;
171
+ }) => import("../core/index.js").LayerProvider<PersistedQueue.PersistedQueueFactory | PersistenceNamespace.Persistence | QueueStatsService | Service | WorkflowEngine.WorkflowEngine, SqlErrorNamespace.SqlError, undefined>;
171
172
  /**
172
173
  * The default job-stack node — every built-in definition over the package's
173
174
  * documented jobs database default (`JobsConfigDefaults.dbUrl`,
@@ -175,5 +176,5 @@ export declare const configured: (defs: readonly JobDefinition.Any[], options: {
175
176
  * the `jobs` section omits `dbUrl`. Nothing is connected at import: the
176
177
  * node only holds a lazily-built layer.
177
178
  */
178
- export declare const node: import("../core/index.js").LayerProvider<PersistedQueue.PersistedQueueFactory | PersistenceNamespace.Persistence | Service | WorkflowEngine.WorkflowEngine, SqlErrorNamespace.SqlError, undefined>;
179
+ export declare const node: import("../core/index.js").LayerProvider<PersistedQueue.PersistedQueueFactory | PersistenceNamespace.Persistence | QueueStatsService | Service | WorkflowEngine.WorkflowEngine, SqlErrorNamespace.SqlError, undefined>;
179
180
  export {};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Queue statistics — drain visibility for the status surfaces.
3
+ *
4
+ * The durable queue's own API (`PersistedQueueStore`: offer/take/cleanup)
5
+ * exposes no count, so pending work is invisible to callers once enqueued:
6
+ * after `memory_index` returns `pendingEmbeddings: N` an agent has no way to
7
+ * ask "how much is still draining?" — it guesses, sleeps, and retries.
8
+ *
9
+ * This service answers that with ONE grouped COUNT over the queue table
10
+ * (`effect_queue`, the table `PersistedQueue.layerStoreSql` creates). Only
11
+ * `state = 'pending'` rows are counted — offered but NOT YET FINISHED.
12
+ * Taking an element does not change its state (it stamps `acquired_at` /
13
+ * `acquired_by`); completion or failure moves it to `completed` / `failed`.
14
+ * So the count is "outstanding work", in-flight included. `completed` rows
15
+ * are dedup records and `failed` rows are dead letters — neither is counted.
16
+ *
17
+ * The internal {@link RESUME_QUEUE} is excluded by design: it carries
18
+ * cross-process wake-up signals for suspended executions, and a signal row
19
+ * outlives the work it points at (the engine resumes in-process too, leaving
20
+ * the durable row pending forever). Counting it would make "is anything
21
+ * still running?" unanswerable — the question this service exists for.
22
+ *
23
+ * It lives beside the stack that owns the queue (the same `SqlClient` the
24
+ * engine and queue store share), so the status surfaces can report drain
25
+ * state without opening a second connection or reaching into `jobs.db`.
26
+ */
27
+ import { Context, Effect, Layer } from "effect";
28
+ import { SqlClient, SqlError as SqlErrorNamespace } from "effect/sql";
29
+ type SqlError = SqlErrorNamespace.SqlError;
30
+ /** Pending elements for one queue (`DurableQueue/<job name>`, `dimple/resume`). */
31
+ export interface QueueStat {
32
+ readonly queue: string;
33
+ readonly pending: number;
34
+ }
35
+ export interface Interface {
36
+ /** Outstanding (offered, not yet finished) elements per queue, queue name
37
+ * ascending. */
38
+ readonly pending: () => Effect.Effect<readonly QueueStat[], SqlError>;
39
+ }
40
+ declare const Service_base: Context.ServiceClass<Service, "@dimple/workflow/QueueStats", Interface>;
41
+ export declare class Service extends Service_base {
42
+ }
43
+ export declare const layer: Layer.Layer<Service, never, SqlClient.SqlClient>;
44
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponraaj/dimple-sdk",
3
- "version": "0.0.0-alpha.13",
3
+ "version": "0.0.0-alpha.14",
4
4
  "private": false,
5
5
  "description": "Local-first memory for AI agents: durable text and code memories with hybrid semantic and lexical retrieval.",
6
6
  "keywords": [