@xdarkicex/openclaw-memory-libravdb 1.4.6 → 1.4.7

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.
Files changed (75) hide show
  1. package/HOOK.md +14 -0
  2. package/README.md +32 -2
  3. package/dist/cli.d.ts +39 -0
  4. package/dist/cli.js +208 -0
  5. package/dist/context-engine.d.ts +56 -0
  6. package/dist/context-engine.js +125 -0
  7. package/dist/dream-promotion.d.ts +47 -0
  8. package/dist/dream-promotion.js +363 -0
  9. package/dist/dream-routing.d.ts +6 -0
  10. package/dist/dream-routing.js +31 -0
  11. package/dist/durable-namespace.d.ts +6 -0
  12. package/dist/durable-namespace.js +24 -0
  13. package/dist/grpc-client.d.ts +23 -0
  14. package/dist/grpc-client.js +104 -0
  15. package/dist/index.d.ts +10 -0
  16. package/dist/index.js +40 -0
  17. package/dist/lifecycle-hooks.d.ts +4 -0
  18. package/dist/lifecycle-hooks.js +64 -0
  19. package/dist/markdown-hash.d.ts +3 -0
  20. package/dist/markdown-hash.js +82 -0
  21. package/dist/markdown-ingest.d.ts +43 -0
  22. package/dist/markdown-ingest.js +464 -0
  23. package/dist/memory-provider.d.ts +4 -0
  24. package/dist/memory-provider.js +13 -0
  25. package/dist/memory-runtime.d.ts +118 -0
  26. package/dist/memory-runtime.js +217 -0
  27. package/dist/plugin-runtime.d.ts +28 -0
  28. package/dist/plugin-runtime.js +127 -0
  29. package/dist/proto/intelligence_kernel/v1/kernel.proto +378 -0
  30. package/dist/recall-cache.d.ts +2 -0
  31. package/dist/recall-cache.js +30 -0
  32. package/dist/rpc-protobuf-codecs.d.ts +70 -0
  33. package/dist/rpc-protobuf-codecs.js +77 -0
  34. package/dist/rpc.d.ts +14 -0
  35. package/dist/rpc.js +121 -0
  36. package/dist/sidecar.d.ts +34 -0
  37. package/dist/sidecar.js +535 -0
  38. package/dist/types.d.ts +163 -0
  39. package/dist/types.js +1 -0
  40. package/docs/contributing.md +14 -13
  41. package/docs/install.md +7 -9
  42. package/docs/installation.md +23 -16
  43. package/docs/uninstall.md +1 -1
  44. package/index.js +2 -0
  45. package/openclaw.plugin.json +2 -2
  46. package/package.json +39 -16
  47. package/packaging/README.md +0 -71
  48. package/packaging/homebrew/libravdbd.rb.tmpl +0 -224
  49. package/packaging/launchd/com.xdarkicex.libravdbd.plist +0 -32
  50. package/packaging/systemd/libravdbd.service +0 -12
  51. package/src/cli.ts +0 -299
  52. package/src/comparison-experiments.ts +0 -128
  53. package/src/context-engine.ts +0 -1645
  54. package/src/continuity.ts +0 -93
  55. package/src/dream-promotion.ts +0 -492
  56. package/src/dream-routing.ts +0 -40
  57. package/src/durable-namespace.ts +0 -34
  58. package/src/index.ts +0 -47
  59. package/src/lifecycle-hooks.ts +0 -96
  60. package/src/markdown-hash.ts +0 -104
  61. package/src/markdown-ingest.ts +0 -627
  62. package/src/memory-provider.ts +0 -25
  63. package/src/memory-runtime.ts +0 -283
  64. package/src/openclaw-plugin-sdk.d.ts +0 -59
  65. package/src/plugin-runtime.ts +0 -119
  66. package/src/recall-cache.ts +0 -34
  67. package/src/recall-utils.ts +0 -131
  68. package/src/rpc.ts +0 -92
  69. package/src/scoring.ts +0 -632
  70. package/src/sidecar.ts +0 -583
  71. package/src/temporal.ts +0 -1031
  72. package/src/tokens.ts +0 -52
  73. package/src/types.ts +0 -278
  74. package/tsconfig.json +0 -20
  75. package/tsconfig.tests.json +0 -12
@@ -0,0 +1,378 @@
1
+ syntax = "proto3";
2
+
3
+ package intelligence_kernel.v1;
4
+
5
+ option go_package = "github.com/xDarkicex/openclaw-memory-libravdb/sidecar/api/proto/intelligence_kernel/v1;kernelpb";
6
+
7
+ import "google/protobuf/struct.proto";
8
+
9
+ // =============================================================================
10
+ // Enums
11
+ // =============================================================================
12
+
13
+ enum ConnectionState {
14
+ CONNECTION_STATE_UNSPECIFIED = 0;
15
+ CONNECTION_STATE_PREAUTH = 1;
16
+ CONNECTION_STATE_AUTHENTICATED = 2;
17
+ CONNECTION_STATE_READY = 3;
18
+ }
19
+
20
+ enum RetrievalTrigger {
21
+ RETRIEVAL_TRIGGER_UNSPECIFIED = 0;
22
+ RETRIEVAL_TRIGGER_NONE = 1;
23
+ RETRIEVAL_TRIGGER_CASCADE_EXHAUSTION = 2;
24
+ RETRIEVAL_TRIGGER_LOW_TOP_SCORE = 3;
25
+ RETRIEVAL_TRIGGER_LOW_SUMMARY_CONFIDENCE = 4;
26
+ RETRIEVAL_TRIGGER_CROSS_SESSION_RAW = 5;
27
+ }
28
+
29
+ enum TemporalPattern {
30
+ TEMPORAL_PATTERN_UNSPECIFIED = 0;
31
+ TEMPORAL_PATTERN_HOW_MANY_DAYS = 1;
32
+ TEMPORAL_PATTERN_HOW_LONG = 2;
33
+ TEMPORAL_PATTERN_BEFORE_OR_AFTER = 3;
34
+ TEMPORAL_PATTERN_SINCE_OR_BETWEEN = 4;
35
+ TEMPORAL_PATTERN_FIRST_OR_EARLIER = 5;
36
+ TEMPORAL_PATTERN_WHEN_DID = 6;
37
+ }
38
+
39
+ enum ComparisonSide {
40
+ COMPARISON_SIDE_UNSPECIFIED = 0;
41
+ COMPARISON_SIDE_SIDE_A = 1;
42
+ COMPARISON_SIDE_SIDE_B = 2;
43
+ COMPARISON_SIDE_NEUTRAL = 3;
44
+ }
45
+
46
+ // =============================================================================
47
+ // Versioning
48
+ // =============================================================================
49
+
50
+ message KernelVersion {
51
+ int32 major = 1;
52
+ int32 minor = 2;
53
+ int32 patch = 3;
54
+ string prerelease = 4;
55
+ }
56
+
57
+ // =============================================================================
58
+ // Session Init & Capabilities
59
+ // =============================================================================
60
+
61
+ message InitializeRequest {
62
+ string client_id = 1;
63
+ repeated ClientCapability client_capabilities = 2;
64
+ map<string, string> client_metadata = 3;
65
+ }
66
+
67
+ message ClientCapability {
68
+ string name = 1;
69
+ string version = 2;
70
+ }
71
+
72
+ message InitializeResponse {
73
+ string session_id = 1;
74
+ ConnectionState connection_state = 2;
75
+ repeated ServerCapability server_capabilities = 3;
76
+ KernelVersion kernel_version = 4;
77
+ map<string, string> server_metadata = 5;
78
+ }
79
+
80
+ message ServerCapability {
81
+ string name = 1;
82
+ string version = 2;
83
+ bool required = 3;
84
+ }
85
+
86
+ // =============================================================================
87
+ // Auth (via gRPC metadata — nonce in response metadata on first call)
88
+ // =============================================================================
89
+
90
+ message AuthChallenge {
91
+ bytes nonce = 1;
92
+ string session_id = 2;
93
+ }
94
+
95
+ message AuthResponse {
96
+ bytes hmac_signature = 1;
97
+ string client_id = 2;
98
+ }
99
+
100
+ // =============================================================================
101
+ // Core Data Structures
102
+ // =============================================================================
103
+
104
+ message Message {
105
+ string role = 1;
106
+ string content = 2;
107
+ string id = 3;
108
+ }
109
+
110
+ message SearchHit {
111
+ string id = 1;
112
+ float score = 2;
113
+ string text = 3;
114
+ google.protobuf.Struct metadata = 4;
115
+ float final_score = 5;
116
+ }
117
+
118
+ message AssembledItem {
119
+ SearchHit hit = 1;
120
+ string role = 2;
121
+ string source = 3;
122
+ bool authored_invariant = 4;
123
+ bool continuity_tail = 5;
124
+ bool elevated_guidance = 6;
125
+ }
126
+
127
+ message ScoredCandidate {
128
+ SearchHit hit = 1;
129
+ float final_score = 2;
130
+ TemporalCandidateMetrics temporal = 3;
131
+ RecoveryCandidateMetrics recovery = 4;
132
+ }
133
+
134
+ message TemporalCandidateMetrics {
135
+ float semantic_score = 1;
136
+ float recency_score = 2;
137
+ float temporal_anchor_density = 3;
138
+ float slot_coverage = 4;
139
+ repeated string slot_matches = 5;
140
+ ComparisonSide comparison_side = 6;
141
+ float comparison_side_witness_score = 7;
142
+ float comparison_slot_recall = 8;
143
+ float comparison_slot_precision = 9;
144
+ float comparison_slot_specificity = 10;
145
+ }
146
+
147
+ message RecoveryCandidateMetrics {
148
+ float lexical_coverage = 1;
149
+ float intent_alignment_bonus = 2;
150
+ RetrievalTrigger trigger = 3;
151
+ string recovery_scope = 4;
152
+ }
153
+
154
+ message ComparisonWitnessPair {
155
+ SearchHit side_a = 1;
156
+ SearchHit side_b = 2;
157
+ int32 total_tokens = 3;
158
+ float pair_score = 4;
159
+ }
160
+
161
+ // =============================================================================
162
+ // Gating Signals
163
+ // =============================================================================
164
+
165
+ message GatingSignals {
166
+ float g = 1;
167
+ float t = 2;
168
+ float h = 3;
169
+ float r = 4;
170
+ float d = 5;
171
+ float p = 6;
172
+ float a = 7;
173
+ float dtech = 8;
174
+ float gconv = 9;
175
+ float gtech = 10;
176
+ float input_freq = 11;
177
+ float mem_saturation = 12;
178
+ }
179
+
180
+ // =============================================================================
181
+ // Temporal Context
182
+ // =============================================================================
183
+
184
+ message TemporalQueryContext {
185
+ bool active = 1;
186
+ float indicator = 2;
187
+ repeated TemporalPattern matched_patterns = 3;
188
+ repeated string slots = 4;
189
+ bool is_comparison_query = 5;
190
+ bool is_duration_interval_query = 6;
191
+ TemporalGuardDecision guard = 7;
192
+ }
193
+
194
+ message TemporalGuardDecision {
195
+ bool should_apply = 1;
196
+ repeated string slots = 2;
197
+ string reason = 3;
198
+ }
199
+
200
+ message DreamQueryContext {
201
+ bool active = 1;
202
+ string collection = 2;
203
+ }
204
+
205
+ // =============================================================================
206
+ // Assembly Config
207
+ // =============================================================================
208
+
209
+ message AssemblyConfig {
210
+ float token_budget_fraction = 1;
211
+ float authored_hard_budget_fraction = 2;
212
+ float authored_soft_budget_fraction = 3;
213
+ float elevated_guidance_budget_fraction = 4;
214
+ int32 continuity_min_turns = 5;
215
+ int32 continuity_tail_budget_tokens = 6;
216
+ int32 top_k = 7;
217
+ int32 coarse_top_k = 8;
218
+ int32 second_pass_top_k = 9;
219
+ float recovery_floor_score = 10;
220
+ int32 recovery_min_top_k = 11;
221
+ float recovery_min_confidence_mean = 12;
222
+ float section7_theta1 = 13;
223
+ float section7_kappa = 14;
224
+ float section7_hop_eta = 15;
225
+ float section7_hop_threshold = 16;
226
+ float section7_authority_recency_lambda = 17;
227
+ float section7_authority_recency_weight = 18;
228
+ float section7_authority_frequency_weight = 19;
229
+ float section7_authority_authored_weight = 20;
230
+ bool disable_reserve_bump = 26;
231
+ bool profiling_enabled = 28;
232
+ }
233
+
234
+ // =============================================================================
235
+ // Assemble Context
236
+ // =============================================================================
237
+
238
+ message AssembleContextRequest {
239
+ string session_id = 1;
240
+ string session_key = 2;
241
+ string user_id = 3;
242
+ string query_text = 4;
243
+ repeated Message visible_messages = 5;
244
+ int32 token_budget = 6;
245
+ AssemblyConfig config = 7;
246
+ bool emit_debug = 8;
247
+ }
248
+
249
+ message AssembleContextResponse {
250
+ repeated Message messages = 1;
251
+ int32 estimated_tokens = 2;
252
+ string system_prompt_addition = 3;
253
+ AssemblyDebug debug = 4;
254
+ }
255
+
256
+ message RecoveryOrderEntry {
257
+ string id = 1;
258
+ string recovery_scope = 2;
259
+ float final_score = 3;
260
+ int32 token_estimate = 4;
261
+ }
262
+
263
+ message AssemblyDebug {
264
+ bool recovery_trigger_fired = 1;
265
+ bool cross_session_raw_recovery = 2;
266
+ int32 recovery_reserve_tokens = 3;
267
+ repeated RecoveryOrderEntry recovery_deduped_order = 4;
268
+ repeated RecoveryOrderEntry recovery_fitted_order = 5;
269
+ repeated string profile_lines = 10;
270
+ }
271
+
272
+ // =============================================================================
273
+ // Ranking
274
+ // =============================================================================
275
+
276
+ message RankCandidatesRequest {
277
+ string session_id = 1;
278
+ string user_id = 2;
279
+ string query_text = 3;
280
+ repeated SearchHit candidates = 4;
281
+ int32 k1 = 5;
282
+ int32 k2 = 6;
283
+ }
284
+
285
+ message RankCandidatesResponse {
286
+ repeated ScoredCandidate ranked = 1;
287
+ }
288
+
289
+ // =============================================================================
290
+ // Ingest & Session
291
+ // =============================================================================
292
+
293
+ message IngestMessageRequest {
294
+ string session_id = 1;
295
+ string session_key = 2;
296
+ string user_id = 3;
297
+ Message message = 4;
298
+ bool is_heartbeat = 5;
299
+ }
300
+
301
+ message IngestMessageResponse {
302
+ bool ingested = 1;
303
+ GatingSignals gating = 2;
304
+ }
305
+
306
+ message AfterTurnRequest {
307
+ string session_id = 1;
308
+ string session_key = 2;
309
+ string user_id = 3;
310
+ repeated Message messages = 4;
311
+ int32 pre_prompt_message_count = 5;
312
+ bool is_heartbeat = 6;
313
+ }
314
+
315
+ message AfterTurnResponse {
316
+ bool ok = 1;
317
+ }
318
+
319
+ message BootstrapSessionRequest {
320
+ string session_id = 1;
321
+ string session_key = 2;
322
+ string user_id = 3;
323
+ }
324
+
325
+ message BootstrapSessionResponse {
326
+ bool ok = 1;
327
+ }
328
+
329
+ message CompactSessionRequest {
330
+ string session_id = 1;
331
+ bool force = 2;
332
+ int32 target_size = 3;
333
+ }
334
+
335
+ message CompactSessionResponse {
336
+ bool ok = 1;
337
+ bool compacted = 2;
338
+ }
339
+
340
+ // =============================================================================
341
+ // Status
342
+ // =============================================================================
343
+
344
+ message GetStatusRequest {}
345
+
346
+ message GetStatusResponse {
347
+ bool ok = 1;
348
+ string message = 2;
349
+ int32 turn_count = 3;
350
+ int32 memory_count = 4;
351
+ string embedding_profile = 5;
352
+ bool abstractive_ready = 6;
353
+ KernelVersion kernel_version = 7;
354
+ }
355
+
356
+ // =============================================================================
357
+ // Service Definition
358
+ // =============================================================================
359
+
360
+ service IntelligenceKernel {
361
+ // Session initialization — first call, returns auth challenge in metadata.
362
+ rpc InitializeSession(InitializeRequest) returns (InitializeResponse);
363
+
364
+ // Full context assembly — replaces 6-8 JSON-RPC calls from TS.
365
+ rpc AssembleContext(AssembleContextRequest) returns (AssembleContextResponse);
366
+
367
+ // Candidate ranking — exposes scoring math for external frameworks.
368
+ rpc RankCandidates(RankCandidatesRequest) returns (RankCandidatesResponse);
369
+
370
+ // Session lifecycle.
371
+ rpc IngestMessage(IngestMessageRequest) returns (IngestMessageResponse);
372
+ rpc AfterTurn(AfterTurnRequest) returns (AfterTurnResponse);
373
+ rpc BootstrapSession(BootstrapSessionRequest) returns (BootstrapSessionResponse);
374
+ rpc CompactSession(CompactSessionRequest) returns (CompactSessionResponse);
375
+
376
+ // Server capabilities.
377
+ rpc GetStatus(GetStatusRequest) returns (GetStatusResponse);
378
+ }
@@ -0,0 +1,2 @@
1
+ import type { RecallCache } from "./types.js";
2
+ export declare function createRecallCache<T = unknown>(): RecallCache<T>;
@@ -0,0 +1,30 @@
1
+ export function createRecallCache() {
2
+ const entries = new Map();
3
+ return {
4
+ put(entry) {
5
+ entries.set(cacheKey(entry.userId, entry.queryText), entry);
6
+ },
7
+ get(key) {
8
+ return entries.get(cacheKey(key.userId, key.queryText));
9
+ },
10
+ take(key) {
11
+ const id = cacheKey(key.userId, key.queryText);
12
+ const hit = entries.get(id);
13
+ if (hit) {
14
+ entries.delete(id);
15
+ }
16
+ return hit;
17
+ },
18
+ clearUser(userId) {
19
+ const prefix = `${userId}\n`;
20
+ for (const key of entries.keys()) {
21
+ if (key.startsWith(prefix)) {
22
+ entries.delete(key);
23
+ }
24
+ }
25
+ },
26
+ };
27
+ }
28
+ function cacheKey(userId, queryText) {
29
+ return `${userId}\n${queryText}`;
30
+ }
@@ -0,0 +1,70 @@
1
+ import { AfterTurnKernelRequest, AfterTurnKernelResponse, AssembleContextInternalRequest, AssembleContextInternalResponse, BootstrapSessionKernelRequest, BootstrapSessionKernelResponse, CompactSessionRequest, CompactSessionResponse, DeleteAuthoredDocumentResponse, DreamPromotionResponse, ExportMemoryResponse, FlushNamespaceResponse, FlushResponse, HealthResponse, IngestMarkdownDocumentResponse, IngestMessageKernelRequest, IngestMessageKernelResponse, MemoryStatusResponse, RankCandidatesRequest, RankCandidatesResponse, SearchTextResponse, SessionLifecycleHintResponse } from "@xdarkicex/libravdb-contracts";
2
+ import type { LifecycleHint } from "./plugin-runtime.js";
3
+ export type RpcMethodCodec<Params = unknown, Result = unknown> = {
4
+ encodeParams(params: Params): Uint8Array;
5
+ decodeResult(bytes: Uint8Array): Result;
6
+ };
7
+ export type RpcMethodName = keyof typeof rpcProtobufCodecs;
8
+ export declare const rpcProtobufCodecs: {
9
+ health: RpcMethodCodec<Record<string, never>, HealthResponse>;
10
+ status: RpcMethodCodec<Record<string, never>, MemoryStatusResponse>;
11
+ flush: RpcMethodCodec<Record<string, never>, FlushResponse>;
12
+ session_lifecycle_hint: RpcMethodCodec<LifecycleHint, SessionLifecycleHintResponse>;
13
+ search_text: RpcMethodCodec<{
14
+ collection: string;
15
+ text: string;
16
+ k?: number;
17
+ excludeIds?: string[];
18
+ }, SearchTextResponse>;
19
+ search_text_collections: RpcMethodCodec<{
20
+ collections: string[];
21
+ text: string;
22
+ k?: number;
23
+ excludeByCollection?: Record<string, unknown>;
24
+ }, SearchTextResponse>;
25
+ list_collection: RpcMethodCodec<{
26
+ collection: string;
27
+ }, SearchTextResponse>;
28
+ list_lifecycle_journal: RpcMethodCodec<{
29
+ sessionId?: string;
30
+ limit?: number;
31
+ }, SearchTextResponse>;
32
+ export_memory: RpcMethodCodec<{
33
+ userId?: string;
34
+ namespace?: string;
35
+ }, ExportMemoryResponse>;
36
+ flush_namespace: RpcMethodCodec<{
37
+ userId?: string;
38
+ namespace?: string;
39
+ }, FlushNamespaceResponse>;
40
+ promote_dream_entries: RpcMethodCodec<{
41
+ userId: string;
42
+ sourceDoc: string;
43
+ sourceRoot?: string;
44
+ sourcePath?: string;
45
+ sourceKind?: string;
46
+ fileHash?: string;
47
+ sourceSize?: number;
48
+ sourceMtimeMs?: number;
49
+ ingestVersion?: number;
50
+ hashBackend?: string;
51
+ entries?: Array<Record<string, unknown>>;
52
+ }, DreamPromotionResponse>;
53
+ ingest_markdown_document: RpcMethodCodec<{
54
+ sourceDoc: string;
55
+ text: string;
56
+ tokenizerId?: string;
57
+ coreDoc?: boolean;
58
+ sourceMeta?: Record<string, unknown>;
59
+ }, IngestMarkdownDocumentResponse>;
60
+ delete_authored_document: RpcMethodCodec<{
61
+ sourceDoc: string;
62
+ }, DeleteAuthoredDocumentResponse>;
63
+ bootstrap_session_kernel: RpcMethodCodec<BootstrapSessionKernelRequest, BootstrapSessionKernelResponse>;
64
+ ingest_message_kernel: RpcMethodCodec<IngestMessageKernelRequest, IngestMessageKernelResponse>;
65
+ after_turn_kernel: RpcMethodCodec<AfterTurnKernelRequest, AfterTurnKernelResponse>;
66
+ assemble_context_internal: RpcMethodCodec<AssembleContextInternalRequest, AssembleContextInternalResponse>;
67
+ compact_session: RpcMethodCodec<CompactSessionRequest, CompactSessionResponse>;
68
+ rank_candidates: RpcMethodCodec<RankCandidatesRequest, RankCandidatesResponse>;
69
+ };
70
+ export declare function getRpcMethodCodec(method: string): RpcMethodCodec<any, any> | undefined;
@@ -0,0 +1,77 @@
1
+ import { AfterTurnKernelRequest, AfterTurnKernelResponse, AssembleContextInternalRequest, AssembleContextInternalResponse, BootstrapSessionKernelRequest, BootstrapSessionKernelResponse, CompactSessionRequest, CompactSessionResponse, DeleteAuthoredDocumentRequest, DeleteAuthoredDocumentResponse, DreamPromotionResponse, ExportMemoryRequest, ExportMemoryResponse, FlushNamespaceRequest, FlushNamespaceResponse, FlushResponse, HealthResponse, IngestMarkdownDocumentRequest, IngestMarkdownDocumentResponse, IngestMessageKernelRequest, IngestMessageKernelResponse, ListCollectionRequest, ListLifecycleJournalRequest, MemoryStatusResponse, PromoteDreamEntriesRequest, RankCandidatesRequest, RankCandidatesResponse, SearchTextCollectionsRequest, SearchTextRequest, SearchTextResponse, SessionLifecycleHintRequest, SessionLifecycleHintResponse, StringList, } from "@xdarkicex/libravdb-contracts";
2
+ function encodeMessage(schema, init) {
3
+ return new schema(init).toBinary();
4
+ }
5
+ function decodeProtobufResult(schema, bytes) {
6
+ return new schema().fromBinary(bytes).toJson();
7
+ }
8
+ function emptyBytes() {
9
+ return new Uint8Array(0);
10
+ }
11
+ function normalizeSearchTextResponse(bytes) {
12
+ const response = decodeProtobufResult(SearchTextResponse, bytes);
13
+ if (!Array.isArray(response.results)) {
14
+ response.results = [];
15
+ }
16
+ for (const item of response.results) {
17
+ if (!item || typeof item !== "object" || Array.isArray(item)) {
18
+ continue;
19
+ }
20
+ if (!item.metadata || typeof item.metadata !== "object" || Array.isArray(item.metadata)) {
21
+ item.metadata = {};
22
+ }
23
+ }
24
+ return response;
25
+ }
26
+ function normalizeExcludeByCollection(value) {
27
+ const normalized = {};
28
+ if (!value) {
29
+ return normalized;
30
+ }
31
+ for (const [collection, raw] of Object.entries(value)) {
32
+ if (raw instanceof StringList) {
33
+ normalized[collection] = raw;
34
+ continue;
35
+ }
36
+ const values = Array.isArray(raw)
37
+ ? raw
38
+ : raw && typeof raw === "object" && Array.isArray(raw.values)
39
+ ? (raw.values)
40
+ : [];
41
+ normalized[collection] = new StringList({ values });
42
+ }
43
+ return normalized;
44
+ }
45
+ function codec(encodeParams, decodeResult) {
46
+ return { encodeParams, decodeResult };
47
+ }
48
+ const encodeEmpty = () => emptyBytes();
49
+ export const rpcProtobufCodecs = {
50
+ health: codec(encodeEmpty, (bytes) => decodeProtobufResult(HealthResponse, bytes)),
51
+ status: codec(encodeEmpty, (bytes) => decodeProtobufResult(MemoryStatusResponse, bytes)),
52
+ flush: codec(encodeEmpty, (bytes) => decodeProtobufResult(FlushResponse, bytes)),
53
+ session_lifecycle_hint: codec((params) => encodeMessage(SessionLifecycleHintRequest, params), (bytes) => decodeProtobufResult(SessionLifecycleHintResponse, bytes)),
54
+ search_text: codec((params) => encodeMessage(SearchTextRequest, params), normalizeSearchTextResponse),
55
+ search_text_collections: codec((params) => encodeMessage(SearchTextCollectionsRequest, {
56
+ collections: params.collections,
57
+ text: params.text,
58
+ k: params.k ?? 0,
59
+ excludeByCollection: normalizeExcludeByCollection(params.excludeByCollection),
60
+ }), normalizeSearchTextResponse),
61
+ list_collection: codec((params) => encodeMessage(ListCollectionRequest, params), normalizeSearchTextResponse),
62
+ list_lifecycle_journal: codec((params) => encodeMessage(ListLifecycleJournalRequest, params), normalizeSearchTextResponse),
63
+ export_memory: codec((params) => encodeMessage(ExportMemoryRequest, params), (bytes) => decodeProtobufResult(ExportMemoryResponse, bytes)),
64
+ flush_namespace: codec((params) => encodeMessage(FlushNamespaceRequest, params), (bytes) => decodeProtobufResult(FlushNamespaceResponse, bytes)),
65
+ promote_dream_entries: codec((params) => encodeMessage(PromoteDreamEntriesRequest, params), (bytes) => decodeProtobufResult(DreamPromotionResponse, bytes)),
66
+ ingest_markdown_document: codec((params) => encodeMessage(IngestMarkdownDocumentRequest, params), (bytes) => decodeProtobufResult(IngestMarkdownDocumentResponse, bytes)),
67
+ delete_authored_document: codec((params) => encodeMessage(DeleteAuthoredDocumentRequest, params), (bytes) => decodeProtobufResult(DeleteAuthoredDocumentResponse, bytes)),
68
+ bootstrap_session_kernel: codec((params) => encodeMessage(BootstrapSessionKernelRequest, params), (bytes) => decodeProtobufResult(BootstrapSessionKernelResponse, bytes)),
69
+ ingest_message_kernel: codec((params) => encodeMessage(IngestMessageKernelRequest, params), (bytes) => decodeProtobufResult(IngestMessageKernelResponse, bytes)),
70
+ after_turn_kernel: codec((params) => encodeMessage(AfterTurnKernelRequest, params), (bytes) => decodeProtobufResult(AfterTurnKernelResponse, bytes)),
71
+ assemble_context_internal: codec((params) => encodeMessage(AssembleContextInternalRequest, params), (bytes) => decodeProtobufResult(AssembleContextInternalResponse, bytes)),
72
+ compact_session: codec((params) => encodeMessage(CompactSessionRequest, params), (bytes) => decodeProtobufResult(CompactSessionResponse, bytes)),
73
+ rank_candidates: codec((params) => encodeMessage(RankCandidatesRequest, params), (bytes) => decodeProtobufResult(RankCandidatesResponse, bytes)),
74
+ };
75
+ export function getRpcMethodCodec(method) {
76
+ return rpcProtobufCodecs[method];
77
+ }
package/dist/rpc.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { RpcCallOptions, SidecarSocket } from "./types.js";
2
+ export declare class RpcClient {
3
+ private readonly socket;
4
+ private readonly options;
5
+ private seq;
6
+ private readonly pending;
7
+ private rxBuf;
8
+ private sentMagic;
9
+ constructor(socket: SidecarSocket, options: RpcCallOptions);
10
+ call<T>(method: string, params: unknown, callOptions?: Partial<RpcCallOptions>): Promise<T>;
11
+ private handleData;
12
+ private dispatchMessage;
13
+ private rejectAll;
14
+ }
package/dist/rpc.js ADDED
@@ -0,0 +1,121 @@
1
+ import { RpcRequest, RpcResponse } from "@xdarkicex/libravdb-contracts";
2
+ import { getRpcMethodCodec } from "./rpc-protobuf-codecs.js";
3
+ export class RpcClient {
4
+ socket;
5
+ options;
6
+ seq = 0n;
7
+ pending = new Map();
8
+ rxBuf = Buffer.alloc(0);
9
+ sentMagic = false;
10
+ constructor(socket, options) {
11
+ this.socket = socket;
12
+ this.options = options;
13
+ // Remove socket.setEncoding("utf8"); completely. The socket must stay binary.
14
+ socket.on("data", (chunk) => this.handleData(chunk));
15
+ socket.on("close", () => {
16
+ this.sentMagic = false; // Force magic byte on next reconnect
17
+ this.rejectAll(new Error("Socket closed"));
18
+ });
19
+ socket.on("error", (error) => this.rejectAll(error));
20
+ }
21
+ async call(method, params, callOptions = {}) {
22
+ const codec = getRpcMethodCodec(method);
23
+ if (!codec) {
24
+ throw new Error(`Unsupported LibraVDB RPC method for protobuf transport: ${method}`);
25
+ }
26
+ return await new Promise((resolve, reject) => {
27
+ const id = ++this.seq;
28
+ const timeoutMs = callOptions.timeoutMs ?? this.options.timeoutMs;
29
+ const timer = setTimeout(() => {
30
+ this.pending.delete(id);
31
+ reject(new Error(`RPC timeout: ${method} (${timeoutMs}ms)`));
32
+ }, timeoutMs);
33
+ this.pending.set(id, { resolve, reject, timer, decodeResult: codec.decodeResult });
34
+ try {
35
+ const envelope = new RpcRequest({
36
+ id,
37
+ method,
38
+ params: codec.encodeParams(params),
39
+ });
40
+ const payload = Buffer.from(envelope.toBinary());
41
+ const header = Buffer.alloc(4);
42
+ header.writeUInt32BE(payload.byteLength, 0);
43
+ const chunks = [];
44
+ if (!this.sentMagic) {
45
+ chunks.push(Buffer.from([0x02]));
46
+ this.sentMagic = true;
47
+ }
48
+ chunks.push(header, payload);
49
+ this.socket.write(Buffer.concat(chunks));
50
+ }
51
+ catch (error) {
52
+ clearTimeout(timer);
53
+ this.pending.delete(id);
54
+ reject(error instanceof Error ? error : new Error(String(error)));
55
+ }
56
+ });
57
+ }
58
+ handleData(chunk) {
59
+ if (chunk.byteLength > 64 << 20) {
60
+ this.socket.destroy();
61
+ return;
62
+ }
63
+ this.rxBuf = Buffer.concat([this.rxBuf, chunk]);
64
+ while (this.rxBuf.byteLength >= 4) {
65
+ const payloadLength = this.rxBuf.readUInt32BE(0);
66
+ if (payloadLength > 64 << 20) {
67
+ this.socket.destroy();
68
+ return;
69
+ }
70
+ const frameSize = 4 + payloadLength;
71
+ // Wait for the full frame to arrive
72
+ if (this.rxBuf.byteLength < frameSize) {
73
+ break;
74
+ }
75
+ const payload = this.rxBuf.subarray(4, frameSize);
76
+ this.rxBuf = this.rxBuf.subarray(frameSize);
77
+ this.dispatchMessage(payload);
78
+ }
79
+ // Compaction guard: release large backing allocations if the remainder is tiny
80
+ if (this.rxBuf.buffer.byteLength > 65536 &&
81
+ this.rxBuf.byteLength < this.rxBuf.buffer.byteLength >>> 2) {
82
+ this.rxBuf = Buffer.from(this.rxBuf);
83
+ }
84
+ }
85
+ dispatchMessage(payload) {
86
+ try {
87
+ const msg = RpcResponse.fromBinary(payload);
88
+ if (typeof msg.id !== "bigint") {
89
+ this.socket.destroy(new Error("Protocol violation: expected bigint message id"));
90
+ return;
91
+ }
92
+ const pending = this.pending.get(msg.id);
93
+ if (!pending) {
94
+ return;
95
+ }
96
+ clearTimeout(pending.timer);
97
+ this.pending.delete(msg.id);
98
+ if (msg.error) {
99
+ const message = msg.error.message?.trim() || `RPC error ${msg.error.code}`;
100
+ pending.reject(new Error(msg.error.code ? `${message} (${msg.error.code})` : message));
101
+ return;
102
+ }
103
+ try {
104
+ pending.resolve(pending.decodeResult(msg.result));
105
+ }
106
+ catch (error) {
107
+ pending.reject(error instanceof Error ? error : new Error(String(error)));
108
+ }
109
+ }
110
+ catch {
111
+ // Ignore malformed frames
112
+ }
113
+ }
114
+ rejectAll(error) {
115
+ for (const [id, pending] of this.pending.entries()) {
116
+ clearTimeout(pending.timer);
117
+ this.pending.delete(id);
118
+ pending.reject(error);
119
+ }
120
+ }
121
+ }