@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.
- package/dist/brain-provider.d.ts +264 -0
- package/dist/brain-provider.d.ts.map +1 -0
- package/dist/brain-provider.js +35 -0
- package/dist/brain-provider.js.map +1 -0
- package/dist/conversation.d.ts +20 -0
- package/dist/conversation.d.ts.map +1 -0
- package/dist/conversation.js +13 -0
- package/dist/conversation.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/search.d.ts +72 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +17 -0
- package/dist/search.js.map +1 -0
- package/package.json +1 -1
|
@@ -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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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"}
|
package/dist/search.d.ts
ADDED
|
@@ -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