@maximem/synap-js-sdk 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/MIGRATING.md +147 -0
  2. package/README.md +95 -82
  3. package/bin/synap-js-sdk.js +45 -122
  4. package/dist/anticipation-cache-ARYEEKMU.cjs +10 -0
  5. package/dist/anticipation-cache-ARYEEKMU.cjs.map +1 -0
  6. package/dist/anticipation-cache-BMVF5sXb.d.cts +190 -0
  7. package/dist/anticipation-cache-BMVF5sXb.d.ts +190 -0
  8. package/dist/anticipation-cache-H7HEVWQC.js +10 -0
  9. package/dist/anticipation-cache-H7HEVWQC.js.map +1 -0
  10. package/dist/chunk-5SC3ELNK.js +856 -0
  11. package/dist/chunk-5SC3ELNK.js.map +1 -0
  12. package/dist/chunk-6LDUDKHS.js +832 -0
  13. package/dist/chunk-6LDUDKHS.js.map +1 -0
  14. package/dist/chunk-HR5Y3KXS.cjs +172 -0
  15. package/dist/chunk-HR5Y3KXS.cjs.map +1 -0
  16. package/dist/chunk-QBCVMPGK.js +28 -0
  17. package/dist/chunk-QBCVMPGK.js.map +1 -0
  18. package/dist/chunk-RB57I2IQ.cjs +832 -0
  19. package/dist/chunk-RB57I2IQ.cjs.map +1 -0
  20. package/dist/chunk-T3NZBIV2.js +172 -0
  21. package/dist/chunk-T3NZBIV2.js.map +1 -0
  22. package/dist/chunk-VXRCBMCY.cjs +856 -0
  23. package/dist/chunk-VXRCBMCY.cjs.map +1 -0
  24. package/dist/chunk-ZKOJDUN4.cjs +28 -0
  25. package/dist/chunk-ZKOJDUN4.cjs.map +1 -0
  26. package/dist/env-55ULHNJZ.cjs +11 -0
  27. package/dist/env-55ULHNJZ.cjs.map +1 -0
  28. package/dist/env-QCUKKW36.js +11 -0
  29. package/dist/env-QCUKKW36.js.map +1 -0
  30. package/dist/grpc/index.cjs +87 -0
  31. package/dist/grpc/index.cjs.map +1 -0
  32. package/dist/grpc/index.d.cts +162 -0
  33. package/dist/grpc/index.d.ts +162 -0
  34. package/dist/grpc/index.js +87 -0
  35. package/dist/grpc/index.js.map +1 -0
  36. package/dist/index.cjs +2702 -0
  37. package/dist/index.cjs.map +1 -0
  38. package/dist/index.d.cts +1491 -0
  39. package/dist/index.d.ts +1491 -0
  40. package/dist/index.js +2702 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/stream-client-ME5N5NK4.js +7 -0
  43. package/dist/stream-client-ME5N5NK4.js.map +1 -0
  44. package/dist/stream-client-ZN6ADZBR.cjs +7 -0
  45. package/dist/stream-client-ZN6ADZBR.cjs.map +1 -0
  46. package/package.json +68 -23
  47. package/.env.example +0 -39
  48. package/bridge/synap_bridge.py +0 -768
  49. package/src/bridge-manager.js +0 -262
  50. package/src/errors.js +0 -168
  51. package/src/index.js +0 -13
  52. package/src/runtime.js +0 -161
  53. package/src/setup-typescript.js +0 -161
  54. package/src/synap-client.js +0 -464
  55. package/types/index.d.ts +0 -475
@@ -0,0 +1,856 @@
1
+ // src/grpc/descriptor.ts
2
+ var PROTO_SHA = "1a9a098645d1b3cf";
3
+ var SYNAP_PROTO_DESCRIPTOR = {
4
+ "nested": {
5
+ "synap": {
6
+ "nested": {
7
+ "v1": {
8
+ "nested": {
9
+ "SynapService": {
10
+ "methods": {
11
+ "Listen": {
12
+ "requestType": "StreamEvent",
13
+ "requestStream": true,
14
+ "responseType": "StreamResponse",
15
+ "responseStream": true
16
+ },
17
+ "IngestTelemetry": {
18
+ "requestType": "TelemetryEvent",
19
+ "requestStream": true,
20
+ "responseType": "TelemetryAck"
21
+ }
22
+ }
23
+ },
24
+ "StreamEvent": {
25
+ "oneofs": {
26
+ "payload": {
27
+ "oneof": [
28
+ "conversation_event",
29
+ "heartbeat_ping",
30
+ "session_control",
31
+ "context_used",
32
+ "context_assembled"
33
+ ]
34
+ }
35
+ },
36
+ "fields": {
37
+ "conversation_event": {
38
+ "type": "ConversationEvent",
39
+ "id": 1
40
+ },
41
+ "heartbeat_ping": {
42
+ "type": "HeartbeatPing",
43
+ "id": 2
44
+ },
45
+ "session_control": {
46
+ "type": "SessionControl",
47
+ "id": 3
48
+ },
49
+ "context_used": {
50
+ "type": "ContextUsedEvent",
51
+ "id": 4
52
+ },
53
+ "context_assembled": {
54
+ "type": "ContextAssembledEvent",
55
+ "id": 5
56
+ }
57
+ }
58
+ },
59
+ "ContextUsedEvent": {
60
+ "fields": {
61
+ "bundle_id": {
62
+ "type": "string",
63
+ "id": 1
64
+ },
65
+ "conversation_id": {
66
+ "type": "string",
67
+ "id": 2
68
+ },
69
+ "user_id": {
70
+ "type": "string",
71
+ "id": 3
72
+ },
73
+ "customer_id": {
74
+ "type": "string",
75
+ "id": 4
76
+ },
77
+ "served_item_ids": {
78
+ "rule": "repeated",
79
+ "type": "string",
80
+ "id": 5
81
+ },
82
+ "timestamp_ms": {
83
+ "type": "int64",
84
+ "id": 6
85
+ },
86
+ "scope": {
87
+ "type": "string",
88
+ "id": 7
89
+ },
90
+ "source_bundle_ids": {
91
+ "rule": "repeated",
92
+ "type": "string",
93
+ "id": 8
94
+ }
95
+ }
96
+ },
97
+ "ContextAssembledEvent": {
98
+ "fields": {
99
+ "correlation_id": {
100
+ "type": "string",
101
+ "id": 1
102
+ },
103
+ "conversation_id": {
104
+ "type": "string",
105
+ "id": 2
106
+ },
107
+ "user_id": {
108
+ "type": "string",
109
+ "id": 3
110
+ },
111
+ "customer_id": {
112
+ "type": "string",
113
+ "id": 4
114
+ },
115
+ "final_item_ids": {
116
+ "rule": "repeated",
117
+ "type": "string",
118
+ "id": 5
119
+ },
120
+ "final_total_tokens": {
121
+ "type": "int32",
122
+ "id": 6
123
+ },
124
+ "compaction_id": {
125
+ "type": "string",
126
+ "id": 7
127
+ },
128
+ "recent_turn_count": {
129
+ "type": "int32",
130
+ "id": 8
131
+ },
132
+ "compaction_end_timestamp": {
133
+ "type": "string",
134
+ "id": 9
135
+ },
136
+ "assembly_source": {
137
+ "type": "string",
138
+ "id": 10
139
+ },
140
+ "assembly_duration_ms": {
141
+ "type": "int32",
142
+ "id": 11
143
+ },
144
+ "cache_hit": {
145
+ "type": "bool",
146
+ "id": 12
147
+ },
148
+ "timestamp_ms": {
149
+ "type": "int64",
150
+ "id": 13
151
+ },
152
+ "sdk_version": {
153
+ "type": "string",
154
+ "id": 14
155
+ }
156
+ }
157
+ },
158
+ "ConversationEvent": {
159
+ "fields": {
160
+ "event_type": {
161
+ "type": "string",
162
+ "id": 1
163
+ },
164
+ "conversation_id": {
165
+ "type": "string",
166
+ "id": 2
167
+ },
168
+ "user_id": {
169
+ "type": "string",
170
+ "id": 3
171
+ },
172
+ "role": {
173
+ "type": "string",
174
+ "id": 4
175
+ },
176
+ "content": {
177
+ "type": "string",
178
+ "id": 5
179
+ },
180
+ "customer_id": {
181
+ "type": "string",
182
+ "id": 6
183
+ },
184
+ "session_id": {
185
+ "type": "string",
186
+ "id": 7
187
+ },
188
+ "metadata": {
189
+ "keyType": "string",
190
+ "type": "string",
191
+ "id": 8
192
+ },
193
+ "timestamp_ms": {
194
+ "type": "int64",
195
+ "id": 9
196
+ },
197
+ "tool_name": {
198
+ "type": "string",
199
+ "id": 10
200
+ },
201
+ "tool_args_json": {
202
+ "type": "string",
203
+ "id": 11
204
+ },
205
+ "search_queries": {
206
+ "rule": "repeated",
207
+ "type": "string",
208
+ "id": 12
209
+ },
210
+ "context_types": {
211
+ "rule": "repeated",
212
+ "type": "string",
213
+ "id": 13
214
+ }
215
+ }
216
+ },
217
+ "HeartbeatPing": {
218
+ "fields": {
219
+ "timestamp_ms": {
220
+ "type": "int64",
221
+ "id": 1
222
+ }
223
+ }
224
+ },
225
+ "SessionControl": {
226
+ "fields": {
227
+ "action": {
228
+ "type": "string",
229
+ "id": 1
230
+ },
231
+ "session_id": {
232
+ "type": "string",
233
+ "id": 2
234
+ },
235
+ "conversation_id": {
236
+ "type": "string",
237
+ "id": 3
238
+ },
239
+ "user_id": {
240
+ "type": "string",
241
+ "id": 4
242
+ },
243
+ "customer_id": {
244
+ "type": "string",
245
+ "id": 5
246
+ }
247
+ }
248
+ },
249
+ "StreamResponse": {
250
+ "oneofs": {
251
+ "payload": {
252
+ "oneof": [
253
+ "context_bundle",
254
+ "heartbeat_pong",
255
+ "signal"
256
+ ]
257
+ }
258
+ },
259
+ "fields": {
260
+ "context_bundle": {
261
+ "type": "ContextBundleProto",
262
+ "id": 1
263
+ },
264
+ "heartbeat_pong": {
265
+ "type": "HeartbeatPong",
266
+ "id": 2
267
+ },
268
+ "signal": {
269
+ "type": "StreamSignal",
270
+ "id": 3
271
+ }
272
+ }
273
+ },
274
+ "HeartbeatPong": {
275
+ "fields": {
276
+ "timestamp_ms": {
277
+ "type": "int64",
278
+ "id": 1
279
+ }
280
+ }
281
+ },
282
+ "StreamSignal": {
283
+ "fields": {
284
+ "signal_type": {
285
+ "type": "string",
286
+ "id": 1
287
+ },
288
+ "reason": {
289
+ "type": "string",
290
+ "id": 2
291
+ },
292
+ "metadata": {
293
+ "keyType": "string",
294
+ "type": "string",
295
+ "id": 3
296
+ }
297
+ }
298
+ },
299
+ "ContextBundleProto": {
300
+ "fields": {
301
+ "bundle_id": {
302
+ "type": "string",
303
+ "id": 1
304
+ },
305
+ "decision_id": {
306
+ "type": "string",
307
+ "id": 2
308
+ },
309
+ "items_by_type": {
310
+ "keyType": "string",
311
+ "type": "ContextItemList",
312
+ "id": 3
313
+ },
314
+ "total_tokens": {
315
+ "type": "int32",
316
+ "id": 4
317
+ },
318
+ "token_budget": {
319
+ "type": "int32",
320
+ "id": 5
321
+ },
322
+ "budget_exceeded": {
323
+ "type": "bool",
324
+ "id": 6
325
+ },
326
+ "retrieval_mode": {
327
+ "type": "string",
328
+ "id": 7
329
+ },
330
+ "sources_queried": {
331
+ "rule": "repeated",
332
+ "type": "string",
333
+ "id": 8
334
+ },
335
+ "degradation_level": {
336
+ "type": "string",
337
+ "id": 9
338
+ },
339
+ "warnings": {
340
+ "rule": "repeated",
341
+ "type": "string",
342
+ "id": 10
343
+ },
344
+ "created_at": {
345
+ "type": "string",
346
+ "id": 11
347
+ },
348
+ "retrieval_time_ms": {
349
+ "type": "int32",
350
+ "id": 12
351
+ },
352
+ "cache_hit": {
353
+ "type": "bool",
354
+ "id": 13
355
+ },
356
+ "search_queries": {
357
+ "rule": "repeated",
358
+ "type": "string",
359
+ "id": 14
360
+ },
361
+ "anticipation_user_id": {
362
+ "type": "string",
363
+ "id": 15
364
+ },
365
+ "anticipation_customer_id": {
366
+ "type": "string",
367
+ "id": 16
368
+ },
369
+ "anticipation_conversation_id": {
370
+ "type": "string",
371
+ "id": 17
372
+ },
373
+ "search_keywords": {
374
+ "rule": "repeated",
375
+ "type": "string",
376
+ "id": 18
377
+ },
378
+ "bundle_type": {
379
+ "type": "string",
380
+ "id": 19
381
+ },
382
+ "conversation_context": {
383
+ "type": "ConversationContextProto",
384
+ "id": 20
385
+ },
386
+ "bundle_confidence": {
387
+ "type": "float",
388
+ "id": 21
389
+ },
390
+ "origin_pattern_id": {
391
+ "type": "string",
392
+ "id": 22
393
+ },
394
+ "ttl_hint_seconds": {
395
+ "type": "int32",
396
+ "id": 23
397
+ }
398
+ }
399
+ },
400
+ "ConversationContextProto": {
401
+ "fields": {
402
+ "summary": {
403
+ "type": "string",
404
+ "id": 1
405
+ },
406
+ "current_state_json": {
407
+ "type": "string",
408
+ "id": 2
409
+ },
410
+ "key_extractions_json": {
411
+ "type": "string",
412
+ "id": 3
413
+ },
414
+ "recent_turns": {
415
+ "rule": "repeated",
416
+ "type": "RecentTurnProto",
417
+ "id": 4
418
+ },
419
+ "compaction_id": {
420
+ "type": "string",
421
+ "id": 5
422
+ },
423
+ "compacted_at": {
424
+ "type": "string",
425
+ "id": 6
426
+ },
427
+ "conversation_id": {
428
+ "type": "string",
429
+ "id": 7
430
+ }
431
+ }
432
+ },
433
+ "RecentTurnProto": {
434
+ "fields": {
435
+ "role": {
436
+ "type": "string",
437
+ "id": 1
438
+ },
439
+ "content": {
440
+ "type": "string",
441
+ "id": 2
442
+ },
443
+ "timestamp": {
444
+ "type": "string",
445
+ "id": 3
446
+ }
447
+ }
448
+ },
449
+ "ContextItemList": {
450
+ "fields": {
451
+ "items": {
452
+ "rule": "repeated",
453
+ "type": "ContextItemProto",
454
+ "id": 1
455
+ }
456
+ }
457
+ },
458
+ "ContextItemProto": {
459
+ "fields": {
460
+ "item_id": {
461
+ "type": "string",
462
+ "id": 1
463
+ },
464
+ "content": {
465
+ "type": "string",
466
+ "id": 2
467
+ },
468
+ "context_type": {
469
+ "type": "string",
470
+ "id": 3
471
+ },
472
+ "source": {
473
+ "type": "string",
474
+ "id": 4
475
+ },
476
+ "similarity_score": {
477
+ "type": "float",
478
+ "id": 5
479
+ },
480
+ "relevance_score": {
481
+ "type": "float",
482
+ "id": 6
483
+ },
484
+ "confidence": {
485
+ "type": "float",
486
+ "id": 7
487
+ },
488
+ "scope": {
489
+ "type": "string",
490
+ "id": 8
491
+ },
492
+ "entity_id": {
493
+ "type": "string",
494
+ "id": 9
495
+ },
496
+ "created_at": {
497
+ "type": "string",
498
+ "id": 10
499
+ },
500
+ "event_date": {
501
+ "type": "string",
502
+ "id": 11
503
+ },
504
+ "valid_until": {
505
+ "type": "string",
506
+ "id": 12
507
+ },
508
+ "temporal_category": {
509
+ "type": "string",
510
+ "id": 13
511
+ },
512
+ "temporal_confidence": {
513
+ "type": "float",
514
+ "id": 14
515
+ }
516
+ }
517
+ },
518
+ "TelemetryEvent": {
519
+ "fields": {
520
+ "event_type": {
521
+ "type": "string",
522
+ "id": 1
523
+ },
524
+ "instance_id": {
525
+ "type": "string",
526
+ "id": 2
527
+ },
528
+ "client_id": {
529
+ "type": "string",
530
+ "id": 3
531
+ },
532
+ "correlation_id": {
533
+ "type": "string",
534
+ "id": 4
535
+ },
536
+ "timestamp_ms": {
537
+ "type": "int64",
538
+ "id": 5
539
+ },
540
+ "latency_ms": {
541
+ "type": "int32",
542
+ "id": 6
543
+ },
544
+ "status": {
545
+ "type": "string",
546
+ "id": 7
547
+ },
548
+ "error_code": {
549
+ "type": "string",
550
+ "id": 8
551
+ },
552
+ "scope": {
553
+ "type": "string",
554
+ "id": 9
555
+ },
556
+ "cache_status": {
557
+ "type": "string",
558
+ "id": 10
559
+ },
560
+ "attempt": {
561
+ "type": "int32",
562
+ "id": 11
563
+ },
564
+ "http_method": {
565
+ "type": "string",
566
+ "id": 12
567
+ },
568
+ "http_path": {
569
+ "type": "string",
570
+ "id": 13
571
+ },
572
+ "http_status_code": {
573
+ "type": "int32",
574
+ "id": 14
575
+ },
576
+ "metadata": {
577
+ "keyType": "string",
578
+ "type": "string",
579
+ "id": 15
580
+ },
581
+ "sdk_version": {
582
+ "type": "string",
583
+ "id": 16
584
+ },
585
+ "batch_id": {
586
+ "type": "string",
587
+ "id": 17
588
+ }
589
+ }
590
+ },
591
+ "TelemetryAck": {
592
+ "fields": {
593
+ "status": {
594
+ "type": "string",
595
+ "id": 1
596
+ },
597
+ "events_received": {
598
+ "type": "int32",
599
+ "id": 2
600
+ }
601
+ }
602
+ }
603
+ }
604
+ }
605
+ }
606
+ }
607
+ }
608
+ };
609
+
610
+ // src/grpc/stream-client.ts
611
+ var UNCACHEABLE_BUNDLE_TYPE = "reactive";
612
+ var MAX_RECONNECT_ATTEMPTS = 10;
613
+ var BACKOFF_BASE_MS = 1e3;
614
+ var BACKOFF_MAX_MS = 3e4;
615
+ var HEARTBEAT_INTERVAL_MS = 3e4;
616
+ var HEARTBEAT_TIMEOUT_MS = 1e4;
617
+ var MAX_MISSED_HEARTBEATS = 3;
618
+ var MIN_TTL_SECONDS = 60;
619
+ var GrpcStreamClient = class {
620
+ host;
621
+ port;
622
+ useTls;
623
+ #state = "disconnected";
624
+ #call = null;
625
+ #reconnectAttempts = 0;
626
+ #lastPongAt = 0;
627
+ #missedHeartbeats = 0;
628
+ #heartbeatTimer = null;
629
+ #shutdownRequested = false;
630
+ #grpc = null;
631
+ #ServiceStub = null;
632
+ #credentials;
633
+ #cache;
634
+ #options;
635
+ #sleep;
636
+ #connectTimeoutMs;
637
+ constructor(credentials, cache, options = {}) {
638
+ this.#credentials = credentials;
639
+ this.#cache = cache;
640
+ this.#options = options;
641
+ this.host = options.host ?? "synap-cloud-prod.maximem.ai";
642
+ this.port = options.port ?? 443;
643
+ this.useTls = options.useTls ?? true;
644
+ this.#sleep = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
645
+ this.#connectTimeoutMs = options.connectTimeoutMs ?? 1e4;
646
+ }
647
+ get currentState() {
648
+ return this.#state;
649
+ }
650
+ get isConnected() {
651
+ return this.#state === "connected";
652
+ }
653
+ async connect() {
654
+ await this.#loadGrpc();
655
+ this.#shutdownRequested = false;
656
+ await this.#establish();
657
+ this.#startHeartbeat();
658
+ }
659
+ async disconnect() {
660
+ this.#shutdownRequested = true;
661
+ this.#stopHeartbeat();
662
+ this.#closeCall();
663
+ this.#setState("closed");
664
+ }
665
+ /** Fire-and-forget: a dropped event must never fail the caller's turn. */
666
+ sendConversationEvent(event) {
667
+ this.#write({ conversation_event: { ...event } });
668
+ }
669
+ sendSessionControl(input) {
670
+ this.#write({ session_control: { ...input } });
671
+ }
672
+ sendContextUsed(event) {
673
+ this.#write({ context_used: { ...event } });
674
+ }
675
+ sendContextAssembled(event) {
676
+ this.#write({ context_assembled: { ...event } });
677
+ }
678
+ #write(msg) {
679
+ if (!this.isConnected || this.#call === null) return;
680
+ try {
681
+ this.#call.write(msg);
682
+ } catch {
683
+ }
684
+ }
685
+ async #loadGrpc() {
686
+ if (this.#grpc !== null) return;
687
+ const [grpcMod, protoMod] = await Promise.all([
688
+ import(
689
+ /* @vite-ignore */
690
+ "@grpc/grpc-js"
691
+ ),
692
+ import(
693
+ /* @vite-ignore */
694
+ "@grpc/proto-loader"
695
+ )
696
+ ]);
697
+ this.#grpc = grpcMod;
698
+ const pkgDef = protoMod.fromJSON(
699
+ SYNAP_PROTO_DESCRIPTOR,
700
+ { keepCase: true, longs: Number, enums: String, defaults: true, oneofs: true }
701
+ );
702
+ const pkg = grpcMod.loadPackageDefinition(pkgDef);
703
+ this.#ServiceStub = pkg.synap.v1.SynapService;
704
+ }
705
+ async #establish() {
706
+ this.#setState("connecting");
707
+ const grpc = this.#grpc;
708
+ const Stub = this.#ServiceStub;
709
+ if (grpc === null || Stub === null) throw new Error("gRPC not loaded");
710
+ const channelCreds = this.useTls ? grpc.credentials.createSsl() : grpc.credentials.createInsecure();
711
+ const stub = new Stub(`${this.host}:${this.port}`, channelCreds, {
712
+ "grpc.keepalive_time_ms": 3e4,
713
+ "grpc.keepalive_timeout_ms": 1e4,
714
+ "grpc.keepalive_permit_without_calls": 1
715
+ });
716
+ await new Promise((resolve, reject) => {
717
+ const deadline = new Date(Date.now() + this.#connectTimeoutMs);
718
+ const waitForReady = stub.waitForReady;
719
+ if (typeof waitForReady !== "function") {
720
+ resolve();
721
+ return;
722
+ }
723
+ waitForReady.call(stub, deadline, (error) => {
724
+ if (error) reject(error);
725
+ else resolve();
726
+ });
727
+ });
728
+ const metadata = new grpc.Metadata();
729
+ metadata.add("authorization", `Bearer ${this.#credentials.apiKey}`);
730
+ metadata.add("x-client-id", this.#credentials.clientId);
731
+ metadata.add("x-instance-id", this.#credentials.instanceId);
732
+ const call = stub["Listen"](metadata);
733
+ call.on("data", (msg) => this.#handleMessage(msg));
734
+ call.on("error", (err) => {
735
+ void this.#handleDisconnect(`error: ${String(err)}`);
736
+ });
737
+ call.on("end", () => {
738
+ void this.#handleDisconnect("server_close");
739
+ });
740
+ this.#call = call;
741
+ this.#setState("connected");
742
+ this.#reconnectAttempts = 0;
743
+ this.#lastPongAt = Date.now();
744
+ }
745
+ #handleMessage(msg) {
746
+ if (msg["context_bundle"]) {
747
+ this.#handleBundle(msg["context_bundle"]);
748
+ return;
749
+ }
750
+ if (msg["heartbeat_pong"]) {
751
+ this.#lastPongAt = Date.now();
752
+ this.#missedHeartbeats = 0;
753
+ return;
754
+ }
755
+ const signal = msg["signal"];
756
+ if (signal?.signal_type === "closing") {
757
+ void this.#handleDisconnect("server_signal_closing");
758
+ }
759
+ }
760
+ #handleBundle(bundle) {
761
+ const bundleType = String(bundle["bundle_type"] ?? "") || "anticipation";
762
+ const conversationId = String(bundle["anticipation_conversation_id"] ?? "");
763
+ if (bundleType !== UNCACHEABLE_BUNDLE_TYPE) this.#store(bundle, bundleType, conversationId);
764
+ if (bundleType === "compaction_update" && conversationId !== "") {
765
+ this.#options.onCompactionUpdate?.(conversationId, bundle);
766
+ }
767
+ this.#options.onContext?.(bundle);
768
+ }
769
+ #store(bundle, bundleType, conversationId) {
770
+ const itemsByType = {};
771
+ for (const [type, list] of Object.entries(bundle["items_by_type"] ?? {})) {
772
+ const items = list?.items;
773
+ itemsByType[type] = items ?? [];
774
+ }
775
+ const ttlHint = Number(bundle["ttl_hint_seconds"] ?? 0);
776
+ this.#cache.store({
777
+ bundleId: String(bundle["bundle_id"] ?? ""),
778
+ // The cache keys on ONE entity. User id wins when present, so a bundle
779
+ // pushed for a user cannot be served to a different user in the same
780
+ // customer; falling back to customer id keeps org-scope bundles usable.
781
+ entityId: String(bundle["anticipation_user_id"] ?? "") || String(bundle["anticipation_customer_id"] ?? "") || null,
782
+ conversationId: conversationId || null,
783
+ itemsByType,
784
+ // 0 means "use the SDK default"; anything else is floored at 60s.
785
+ ttlHintSeconds: ttlHint > 0 ? Math.max(ttlHint, MIN_TTL_SECONDS) : null,
786
+ bundleType,
787
+ searchQueries: [
788
+ ...bundle["search_queries"] ?? [],
789
+ ...bundle["search_keywords"] ?? []
790
+ ]
791
+ });
792
+ }
793
+ async #handleDisconnect(_reason) {
794
+ if (this.#shutdownRequested) return;
795
+ this.#closeCall();
796
+ this.#setState("reconnecting");
797
+ if (this.#reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
798
+ this.#setState("disconnected");
799
+ return;
800
+ }
801
+ const delay = Math.min(
802
+ BACKOFF_BASE_MS * 2 ** this.#reconnectAttempts + Math.random() * 1e3,
803
+ BACKOFF_MAX_MS
804
+ );
805
+ this.#reconnectAttempts += 1;
806
+ await this.#sleep(delay);
807
+ if (this.#shutdownRequested) return;
808
+ try {
809
+ await this.#establish();
810
+ } catch {
811
+ void this.#handleDisconnect("reconnect_failed");
812
+ }
813
+ }
814
+ #startHeartbeat() {
815
+ this.#heartbeatTimer = setInterval(() => {
816
+ if (!this.isConnected || this.#call === null) return;
817
+ const now = Date.now();
818
+ if (now - this.#lastPongAt > HEARTBEAT_TIMEOUT_MS) {
819
+ this.#missedHeartbeats += 1;
820
+ if (this.#missedHeartbeats >= MAX_MISSED_HEARTBEATS) {
821
+ void this.#handleDisconnect("heartbeat_timeout");
822
+ return;
823
+ }
824
+ }
825
+ try {
826
+ this.#call.write({ heartbeat_ping: { timestamp_ms: now } });
827
+ } catch {
828
+ void this.#handleDisconnect("heartbeat_write_error");
829
+ }
830
+ }, HEARTBEAT_INTERVAL_MS);
831
+ this.#heartbeatTimer.unref?.();
832
+ }
833
+ #stopHeartbeat() {
834
+ if (this.#heartbeatTimer !== null) {
835
+ clearInterval(this.#heartbeatTimer);
836
+ this.#heartbeatTimer = null;
837
+ }
838
+ }
839
+ #closeCall() {
840
+ try {
841
+ this.#call?.end();
842
+ } catch {
843
+ }
844
+ this.#call = null;
845
+ }
846
+ #setState(state) {
847
+ this.#state = state;
848
+ this.#options.onStateChange?.(state);
849
+ }
850
+ };
851
+
852
+ export {
853
+ PROTO_SHA,
854
+ GrpcStreamClient
855
+ };
856
+ //# sourceMappingURL=chunk-5SC3ELNK.js.map