@kybernesis/brain-contracts 0.12.0 → 0.14.0

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.
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Layer-2 `BrainProvider` seam (ADR-0016).
3
+ *
4
+ * A coarse-grained, consumer-facing facade over brain *operations* —
5
+ * `remember` / `addNote` / `query` / `timeline` / entity ops / `stats` /
6
+ * `sleep`. It sits one level ABOVE the Layer-3 `StorageProvider` (persistence)
7
+ * and is the seam a consumer swaps to point a brain at a local engine
8
+ * (`LocalBrainProvider`, shipped from `brain-core`) or — in a later, Ian-gated
9
+ * phase — a remote cloud service (`RemoteBrainProvider` → Arcana).
10
+ *
11
+ * Bound-tenant model: a provider instance is bound to ONE tenant at
12
+ * construction (e.g. `createLocalBrainProvider(t)`); methods do NOT take a
13
+ * `TenantContext` parameter. "A BrainProvider is one brain." This mirrors KAD's
14
+ * `new LocalBrainProvider(entry)` and maps 1:1 onto Arcana's
15
+ * `/brain/:workspace/*` endpoints (the workspace is fixed per instance).
16
+ *
17
+ * Interface invariants:
18
+ * - Every method is async (uniform over local + HTTP-remote).
19
+ * - Returned object fields are snake_case (the canonical brain-row shape —
20
+ * see the header note in `entity.ts`).
21
+ * - It never exposes a `Database` handle or a Layer-3 provider — only domain
22
+ * operations cross this seam.
23
+ * - Coarse-grained ("chunky, not chatty") so remote latency stays acceptable.
24
+ *
25
+ * WRITE-CONSISTENCY CAVEAT (the one genuine semantic leak, per ADR-0016):
26
+ * A `LocalBrainProvider` write is *immediately* readable — write-then-read
27
+ * sees the write. A future `RemoteBrainProvider` may queue writes for
28
+ * outbound delivery, so its writes are *eventually* consistent: a read
29
+ * immediately after a write may not yet observe it. Callers MUST NOT assume
30
+ * write-then-immediately-read works identically against a remote brain. The
31
+ * write methods (`remember`, `addNote`, `upsertEntity`, `pinEntity`) carry
32
+ * this caveat in their own JSDoc.
33
+ */
34
+ import type { TenantContext } from './tenant.js';
35
+ import type { ConversationInput } from './conversation.js';
36
+ import type { HybridSearchResult, HybridSearchOptions } from './search.js';
37
+ import type { TimelineEvent } from './timeline.js';
38
+ import type { TimelineQuery, EntityRelatedHit } from './storage.js';
39
+ import type { Entity, EntityMention } from './entity.js';
40
+ import type { EntityType, RelationshipType } from './constants.js';
41
+ /** Options common to all write operations. */
42
+ export interface WriteOpts {
43
+ /**
44
+ * Stable identifier for idempotent retries. RESERVED for the future
45
+ * `RemoteBrainProvider`, which sends it as the `Idempotency-Key` HTTP header
46
+ * (24h dedup, cached-response replay) so a partial migration can resume
47
+ * cleanly. `LocalBrainProvider` IGNORES it — local writes are already
48
+ * idempotent via the single-writer queue + UNIQUE constraints. Chat-turn
49
+ * callers can omit it.
50
+ */
51
+ idempotencyKey?: string;
52
+ }
53
+ /** Input for {@link BrainProvider.addNote}. Long-form note ingestion. */
54
+ export interface NoteInput {
55
+ content: string;
56
+ title?: string;
57
+ type?: 'conversation' | 'idea' | 'file' | 'transcript' | 'note' | 'intake';
58
+ source_path?: string;
59
+ }
60
+ /** Result of {@link BrainProvider.addNote}. */
61
+ export interface NoteResult {
62
+ ok: true;
63
+ title: string;
64
+ type: string;
65
+ /**
66
+ * ESTIMATED segment count (`ceil(content.length / 250)`), NOT the number of
67
+ * vector chunks actually indexed. A CLI-feedback figure for parity with KAD;
68
+ * do not treat it as an embedding count.
69
+ */
70
+ segments: number;
71
+ /**
72
+ * BEST-EFFORT count of entities touched by this note, derived from a global
73
+ * entity-count delta taken before/after the write. It is NOT exact per-note
74
+ * attribution and SKEWS under concurrent writes to the same brain (another
75
+ * write landing between the snapshots is counted here). A CLI-feedback
76
+ * figure, not an audit number.
77
+ */
78
+ entities_touched: number;
79
+ }
80
+ /** Result of {@link BrainProvider.pinEntity}; `null` when the entity isn't found. */
81
+ export interface PinResult {
82
+ ok: true;
83
+ id: number;
84
+ name: string;
85
+ pinned: boolean;
86
+ }
87
+ /** A pinned entity, as returned by {@link BrainProvider.getPinnedEntities}. */
88
+ export interface PinnedEntity {
89
+ id: number;
90
+ name: string;
91
+ type: string;
92
+ mention_count: number;
93
+ last_seen: string;
94
+ }
95
+ /** Result of {@link BrainProvider.recallEntity}; the full entity context. */
96
+ export interface EntityRecall {
97
+ entity: Entity;
98
+ mentions: EntityMention[];
99
+ related_entities: EntityRelatedHit[];
100
+ }
101
+ /**
102
+ * A single entity↔entity edge in the renderable entity graph
103
+ * ({@link BrainProvider.graph}). Endpoints are entity ids (the `nodes` array
104
+ * carries the full {@link Entity} rows). Field names mirror KAD's
105
+ * `GET /brain/graph` entity-relation edge sub-shape (`relationship` /
106
+ * `confidence`) minus its UI-only id namespacing, so a KAD/Arcana renderer maps
107
+ * `source_id`→`e:<id>` without reshaping.
108
+ */
109
+ export interface BrainGraphEdge {
110
+ source_id: number;
111
+ target_id: number;
112
+ relationship: RelationshipType;
113
+ confidence: number;
114
+ rationale?: string;
115
+ }
116
+ /**
117
+ * A renderable slice of the **entity** graph — entity nodes + typed entity↔entity
118
+ * edges, drawn from `entity-graph.db` ONLY.
119
+ *
120
+ * SCOPE (deliberate): this is the entity-graph primitive, NOT KAD's full
121
+ * `GET /brain/graph` assembly. KAD's route is a HOST-level unified graph that
122
+ * also folds in timeline-event nodes, sleep `memory_edges`, temporal-fact nodes
123
+ * and disk-scanned notes — work that crosses three DBs and walks the filesystem,
124
+ * which the kernel must not do (the kernel never touches the fs). A host that
125
+ * wants the full canvas composes this entity slice with `timeline()` + its own
126
+ * sleep/disk sources; the library owns only the entity graph.
127
+ */
128
+ export interface BrainGraph {
129
+ /** Entity nodes, most-mentioned (most-connected) first — the graph anchors. */
130
+ nodes: Entity[];
131
+ /** Typed entity↔entity edges among `nodes` (closed: both endpoints are nodes). */
132
+ edges: BrainGraphEdge[];
133
+ }
134
+ /** Brain-wide counts, as returned by {@link BrainProvider.stats}. */
135
+ export interface BrainStats {
136
+ timeline_rows: number;
137
+ fact_rows: number;
138
+ entity_rows: number;
139
+ vector_rows: number;
140
+ vector_backend: string;
141
+ }
142
+ /**
143
+ * Per-tenant brain operations. Bound to ONE tenant at construction; methods do
144
+ * NOT take a `TenantContext`. Obtain a local instance via
145
+ * `createLocalBrainProvider(t)` (from `@kybernesis/brain-core`).
146
+ */
147
+ export interface BrainProvider {
148
+ /**
149
+ * Full store-conversation pipeline (timeline + entities + facts + embeddings).
150
+ *
151
+ * Write-consistency: local writes are immediately readable; a future remote
152
+ * provider may queue this write (eventually consistent — see the interface
153
+ * note). `opts.idempotencyKey` is reserved for the remote provider;
154
+ * `LocalBrainProvider` ignores it.
155
+ */
156
+ remember(input: ConversationInput, opts?: WriteOpts): Promise<void>;
157
+ /**
158
+ * Long-form note ingestion. Defaults `type='note'`, `channel='note'`.
159
+ *
160
+ * Write-consistency: same caveat as {@link remember} — local is immediate,
161
+ * remote may be eventually consistent. `opts.idempotencyKey` reserved for the
162
+ * remote provider; ignored locally.
163
+ */
164
+ addNote(input: NoteInput, opts?: WriteOpts): Promise<NoteResult>;
165
+ /**
166
+ * Idempotent entity upsert, keyed on (normalized_name, type) — the SAME name
167
+ * under a DIFFERENT type is a distinct entity (so `created` can be `true` for
168
+ * a name that already exists under another type). `type` defaults to `'topic'`.
169
+ * Returns the entity id and whether this call inserted a new row.
170
+ *
171
+ * `created` is best-effort: when several same-name entities exist across
172
+ * different types, a re-upsert of an existing one may report a false
173
+ * `created: true` (the pre-check resolves by name only). Exact tracking would
174
+ * need a storage-level created signal — treat `created` as a hint, not a gate.
175
+ *
176
+ * `type` is constrained to `EntityType` at compile time; the adapter also
177
+ * validates it at the seam and throws a clean error (naming the bad value +
178
+ * the allowed set) rather than surfacing a storage-layer CHECK violation.
179
+ *
180
+ * Write-consistency: local is immediate; remote may be eventually consistent.
181
+ */
182
+ upsertEntity(body: {
183
+ name: string;
184
+ type?: EntityType;
185
+ }, opts?: WriteOpts): Promise<{
186
+ id: string;
187
+ created: boolean;
188
+ }>;
189
+ /**
190
+ * Toggle `is_pinned` on an entity. Resolves a numeric id or a (case-
191
+ * insensitive) name. Returns `null` if no entity matches.
192
+ *
193
+ * Write-consistency: local is immediate; remote may be eventually consistent.
194
+ */
195
+ pinEntity(nameOrId: string, pinned: boolean, opts?: WriteOpts): Promise<PinResult | null>;
196
+ /**
197
+ * Hybrid retrieval (semantic + keyword + temporal + graph, RRF-fused).
198
+ *
199
+ * REMOTE-PHASE RISK: `HybridSearchOptions.after`/`before` are `Date` objects,
200
+ * which do not JSON-serialize faithfully over the wire. A future
201
+ * `RemoteBrainProvider` MUST marshal these Date↔ISO (and back) at the
202
+ * transport boundary. The `Date` type is intentional and stays (KAD depends
203
+ * on it); this is a transport concern for the remote adapter, not an
204
+ * interface change.
205
+ */
206
+ query(query: string, opts?: HybridSearchOptions): Promise<HybridSearchResult[]>;
207
+ /** Timeline events, newest-first, with optional filters. */
208
+ timeline(opts?: TimelineQuery): Promise<TimelineEvent[]>;
209
+ /** Full entity context (entity + recent mentions + related entities), or `null`. */
210
+ recallEntity(name: string): Promise<EntityRecall | null>;
211
+ /** Pinned entities, most-mentioned first. */
212
+ getPinnedEntities(): Promise<PinnedEntity[]>;
213
+ /**
214
+ * Renderable slice of the entity graph — nodes (most-mentioned first) + the
215
+ * typed edges among them. Coarse-grained: ONE call returns the whole
216
+ * renderable graph (chunky, not chatty). `opts.limit` caps the node count
217
+ * (default 50); edges are restricted to pairs where both endpoints are nodes,
218
+ * so the returned graph is always closed/drawable. Entity-graph.db only — see
219
+ * {@link BrainGraph} for why this is the entity slice, not KAD's full assembly.
220
+ */
221
+ graph(opts?: {
222
+ limit?: number;
223
+ }): Promise<BrainGraph>;
224
+ /**
225
+ * Flat entity list for an entities table/browser, most-mentioned (most-
226
+ * relevant) first, optionally filtered by `type`. `opts.limit` defaults to 50.
227
+ */
228
+ listEntities(opts?: {
229
+ limit?: number;
230
+ type?: EntityType;
231
+ }): Promise<Entity[]>;
232
+ /** Brain-wide counts (timeline / facts / entities / vectors). */
233
+ stats(): Promise<BrainStats>;
234
+ /**
235
+ * Run a full sleep cycle synchronously and return its metrics. `cfg` is an
236
+ * optional partial config override. Bound-tenant — no `TenantContext` param.
237
+ */
238
+ sleep(cfg?: SleepCycleConfig): Promise<SleepCycleMetrics>;
239
+ }
240
+ /**
241
+ * Sleep config override for {@link BrainProvider.sleep}.
242
+ *
243
+ * Opaque at the contract level so `brain-contracts` stays decoupled from the
244
+ * sleep tuning knobs (which live in `brain-core`). The concrete
245
+ * `LocalBrainProvider` accepts the real `Partial<SleepConfig>`; callers that
246
+ * want the typed config import `SleepConfig` from `@kybernesis/brain-core` and
247
+ * pass it here (assignable, since this is `unknown`).
248
+ */
249
+ export type SleepCycleConfig = unknown;
250
+ /**
251
+ * Sleep metrics returned by {@link BrainProvider.sleep}.
252
+ *
253
+ * Opaque at the contract level (the full per-step `RunMetrics` shape lives in
254
+ * `brain-core`, which is one level below `brain-contracts`). The concrete
255
+ * `LocalBrainProvider.sleep` returns the real `SleepRunMetrics`; callers that
256
+ * want the typed metrics import `SleepRunMetrics` from `@kybernesis/brain-core`
257
+ * and narrow this `unknown` to it. Keeping it opaque is what lets one interface
258
+ * serve both the local provider and a future remote one without pulling sleep
259
+ * internals into the shared contract.
260
+ */
261
+ export type SleepCycleMetrics = unknown;
262
+ /** Re-export for adapters that build a provider bound to a tenant. */
263
+ export type { TenantContext };
264
+ //# sourceMappingURL=brain-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brain-provider.d.ts","sourceRoot":"","sources":["../src/brain-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Layer-2 `BrainProvider` seam (ADR-0016).
3
+ *
4
+ * A coarse-grained, consumer-facing facade over brain *operations* —
5
+ * `remember` / `addNote` / `query` / `timeline` / entity ops / `stats` /
6
+ * `sleep`. It sits one level ABOVE the Layer-3 `StorageProvider` (persistence)
7
+ * and is the seam a consumer swaps to point a brain at a local engine
8
+ * (`LocalBrainProvider`, shipped from `brain-core`) or — in a later, Ian-gated
9
+ * phase — a remote cloud service (`RemoteBrainProvider` → Arcana).
10
+ *
11
+ * Bound-tenant model: a provider instance is bound to ONE tenant at
12
+ * construction (e.g. `createLocalBrainProvider(t)`); methods do NOT take a
13
+ * `TenantContext` parameter. "A BrainProvider is one brain." This mirrors KAD's
14
+ * `new LocalBrainProvider(entry)` and maps 1:1 onto Arcana's
15
+ * `/brain/:workspace/*` endpoints (the workspace is fixed per instance).
16
+ *
17
+ * Interface invariants:
18
+ * - Every method is async (uniform over local + HTTP-remote).
19
+ * - Returned object fields are snake_case (the canonical brain-row shape —
20
+ * see the header note in `entity.ts`).
21
+ * - It never exposes a `Database` handle or a Layer-3 provider — only domain
22
+ * operations cross this seam.
23
+ * - Coarse-grained ("chunky, not chatty") so remote latency stays acceptable.
24
+ *
25
+ * WRITE-CONSISTENCY CAVEAT (the one genuine semantic leak, per ADR-0016):
26
+ * A `LocalBrainProvider` write is *immediately* readable — write-then-read
27
+ * sees the write. A future `RemoteBrainProvider` may queue writes for
28
+ * outbound delivery, so its writes are *eventually* consistent: a read
29
+ * immediately after a write may not yet observe it. Callers MUST NOT assume
30
+ * write-then-immediately-read works identically against a remote brain. The
31
+ * write methods (`remember`, `addNote`, `upsertEntity`, `pinEntity`) carry
32
+ * this caveat in their own JSDoc.
33
+ */
34
+ export {};
35
+ //# sourceMappingURL=brain-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brain-provider.js","sourceRoot":"","sources":["../src/brain-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Conversation-ingest DTO — lifted from `brain-core/src/store-conversation.ts`
3
+ * so the Layer-2 `BrainProvider` interface (which lives here in brain-contracts)
4
+ * can reference `remember`'s input shape without contracts depending on
5
+ * brain-core.
6
+ *
7
+ * Plain, self-contained shape (no runtime behaviour). `brain-core` imports it
8
+ * back and re-exports it unchanged, so existing `@kybernesis/brain-core`
9
+ * consumers (KAD) import `ConversationInput` from the same place as before —
10
+ * this move is additive and non-breaking.
11
+ */
12
+ export interface ConversationInput {
13
+ prompt: string;
14
+ response: string;
15
+ channel: string;
16
+ timestamp?: string;
17
+ metadata?: Record<string, unknown>;
18
+ eventType?: 'conversation' | 'idea' | 'file' | 'transcript' | 'note' | 'intake';
19
+ }
20
+ //# sourceMappingURL=conversation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../src/conversation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,SAAS,CAAC,EAAE,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,MAAM,GAAG,QAAQ,CAAC;CACjF"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Conversation-ingest DTO — lifted from `brain-core/src/store-conversation.ts`
3
+ * so the Layer-2 `BrainProvider` interface (which lives here in brain-contracts)
4
+ * can reference `remember`'s input shape without contracts depending on
5
+ * brain-core.
6
+ *
7
+ * Plain, self-contained shape (no runtime behaviour). `brain-core` imports it
8
+ * back and re-exports it unchanged, so existing `@kybernesis/brain-core`
9
+ * consumers (KAD) import `ConversationInput` from the same place as before —
10
+ * this move is additive and non-breaking.
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=conversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../src/conversation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
package/dist/index.d.ts CHANGED
@@ -7,4 +7,7 @@ export * from './sleep.js';
7
7
  export * from './storage.js';
8
8
  export * from './logger.js';
9
9
  export * from './reconcile-diff.js';
10
+ export * from './conversation.js';
11
+ export * from './search.js';
12
+ export * from './brain-provider.js';
10
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -7,4 +7,7 @@ export * from './sleep.js';
7
7
  export * from './storage.js';
8
8
  export * from './logger.js';
9
9
  export * from './reconcile-diff.js';
10
+ export * from './conversation.js';
11
+ export * from './search.js';
12
+ export * from './brain-provider.js';
10
13
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Hybrid-search DTOs — lifted from `brain-core/src/hybrid-search.ts` so the
3
+ * Layer-2 `BrainProvider` interface (which lives here in brain-contracts) can
4
+ * reference them without contracts depending on brain-core.
5
+ *
6
+ * These are plain, self-contained shapes (no runtime behaviour). `brain-core`
7
+ * imports them back and re-exports them unchanged, so existing
8
+ * `@kybernesis/brain-core` consumers (KAD) import them from the same place as
9
+ * before — this move is additive and non-breaking.
10
+ *
11
+ * Field names are snake_case where they mirror DB-derived rows (the load-bearing
12
+ * convention — see the header note in `entity.ts`); the camelCase fields here
13
+ * (`semanticScore`, `hybridScore`, …) are pre-existing computed scores carried
14
+ * over verbatim from KAD's hybrid-search result, NOT new additions.
15
+ */
16
+ export interface HybridSearchResult {
17
+ id: string;
18
+ title: string;
19
+ content: string;
20
+ source_path: string;
21
+ timestamp: string;
22
+ type: string;
23
+ tier?: string;
24
+ priority?: number;
25
+ tags?: string[];
26
+ semanticScore: number;
27
+ metadataScore: number;
28
+ hybridScore: number;
29
+ matchType: 'semantic' | 'keyword' | 'both';
30
+ relatedMemories?: string[];
31
+ /** Raw vector distance from the semantic arm (lower = closer), BEFORE RRF
32
+ * rank-collapse — exposed so callers can judge match strength (RRF otherwise
33
+ * discards it). NOTE: this is the raw store distance (L2 via vec_distance_l2);
34
+ * its scale depends on the injected embedder (unbounded; ~[0,2] only for
35
+ * unit-normalized vectors). NOT a calibrated 0–1 similarity — callers must
36
+ * calibrate to their embedder. Undefined if not a semantic hit. Additive. */
37
+ rawSemanticDistance?: number;
38
+ /** Raw keyword-arm relevance score (higher = better), pre-RRF. Undefined if
39
+ * not a keyword hit. */
40
+ rawKeywordScore?: number;
41
+ }
42
+ export interface HybridSearchOptions {
43
+ limit?: number;
44
+ tier?: 'hot' | 'warm' | 'archive' | 'all';
45
+ minPriority?: number;
46
+ includeRelated?: boolean;
47
+ semanticWeight?: number;
48
+ metadataWeight?: number;
49
+ type?: 'conversation' | 'idea' | 'file' | 'transcript' | 'note';
50
+ entity?: string;
51
+ entityMatch?: 'all' | 'any';
52
+ after?: Date;
53
+ before?: Date;
54
+ expandQuery?: boolean;
55
+ factFirst?: boolean;
56
+ rerank?: boolean;
57
+ /** Run the relational graph arm (Channel 5) when the query parses as a
58
+ * relationship question. Default ON — but the parser gate means it only
59
+ * fires for relational queries, so non-relational retrieval is unaffected.
60
+ * Set false to disable entirely (kill switch). */
61
+ useRelational?: boolean;
62
+ /** Run the entity-LOOKUP archetype ("what is X / who is X") within the
63
+ * relational arm. Default OFF — measured break-even on knowledge brains
64
+ * (+entity, −recall, net +1 probe; gap-analysis #8). Opt in for entity/
65
+ * lookup-heavy corpora (e.g. Arcana). Requires useRelational. */
66
+ useLookup?: boolean;
67
+ /** KYB-80: weight fact scores by read-time decayed confidence in the
68
+ * factFirst path. Default OFF — gated on brain-bench. No effect unless
69
+ * factFirst is also set. */
70
+ useDecay?: boolean;
71
+ }
72
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;IAC3C,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B;;;;;kFAK8E;IAC9E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;6BACyB;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,MAAM,CAAC;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAC5B,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;uDAGmD;IACnD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;sEAGkE;IAClE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;iCAE6B;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
package/dist/search.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Hybrid-search DTOs — lifted from `brain-core/src/hybrid-search.ts` so the
3
+ * Layer-2 `BrainProvider` interface (which lives here in brain-contracts) can
4
+ * reference them without contracts depending on brain-core.
5
+ *
6
+ * These are plain, self-contained shapes (no runtime behaviour). `brain-core`
7
+ * imports them back and re-exports them unchanged, so existing
8
+ * `@kybernesis/brain-core` consumers (KAD) import them from the same place as
9
+ * before — this move is additive and non-breaking.
10
+ *
11
+ * Field names are snake_case where they mirror DB-derived rows (the load-bearing
12
+ * convention — see the header note in `entity.ts`); the camelCase fields here
13
+ * (`semanticScore`, `hybridScore`, …) are pre-existing computed scores carried
14
+ * over verbatim from KAD's hybrid-search result, NOT new additions.
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kybernesis/brain-contracts",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Zod schemas, provider interfaces, and shared types for the Kybernesis brain library",
5
5
  "license": "MIT",
6
6
  "author": "David Cruwys (AppyDave)",