@realtimex/sdk 1.0.9 → 1.1.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.
package/dist/index.js CHANGED
@@ -32,11 +32,15 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  ActivitiesModule: () => ActivitiesModule,
34
34
  ApiModule: () => ApiModule,
35
+ LLMModule: () => LLMModule,
36
+ LLMPermissionError: () => LLMPermissionError,
37
+ LLMProviderError: () => LLMProviderError,
35
38
  PermissionDeniedError: () => PermissionDeniedError,
36
39
  PermissionRequiredError: () => PermissionRequiredError,
37
40
  PortModule: () => PortModule,
38
41
  RealtimeXSDK: () => RealtimeXSDK,
39
42
  TaskModule: () => TaskModule,
43
+ VectorStore: () => VectorStore,
40
44
  WebhookModule: () => WebhookModule
41
45
  });
42
46
  module.exports = __toCommonJS(index_exports);
@@ -472,6 +476,384 @@ var PortModule = class {
472
476
  }
473
477
  };
474
478
 
479
+ // src/modules/llm.ts
480
+ var LLMPermissionError = class extends Error {
481
+ constructor(permission, code = "PERMISSION_REQUIRED") {
482
+ super(`Permission required: ${permission}`);
483
+ this.permission = permission;
484
+ this.code = code;
485
+ this.name = "LLMPermissionError";
486
+ }
487
+ };
488
+ var LLMProviderError = class extends Error {
489
+ constructor(message, code = "LLM_ERROR") {
490
+ super(message);
491
+ this.code = code;
492
+ this.name = "LLMProviderError";
493
+ }
494
+ };
495
+ var VectorStore = class {
496
+ constructor(baseUrl, appId) {
497
+ this.baseUrl = baseUrl;
498
+ this.appId = appId;
499
+ }
500
+ get headers() {
501
+ return {
502
+ "Content-Type": "application/json",
503
+ "x-app-id": this.appId
504
+ };
505
+ }
506
+ /**
507
+ * Upsert (insert or update) vectors into storage
508
+ *
509
+ * @example
510
+ * ```ts
511
+ * await sdk.llm.vectors.upsert([
512
+ * { id: 'chunk-1', vector: embeddings[0], metadata: { text: 'Hello', documentId: 'doc-1' } }
513
+ * ], { workspaceId: 'ws-123' });
514
+ * ```
515
+ */
516
+ async upsert(vectors, options = {}) {
517
+ const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/upsert`, {
518
+ method: "POST",
519
+ headers: this.headers,
520
+ body: JSON.stringify({
521
+ vectors,
522
+ workspaceId: options.workspaceId
523
+ })
524
+ });
525
+ const data = await response.json();
526
+ if (data.code === "PERMISSION_REQUIRED") {
527
+ throw new LLMPermissionError(data.permission || "vectors.write");
528
+ }
529
+ return data;
530
+ }
531
+ /**
532
+ * Query similar vectors by embedding
533
+ *
534
+ * @example
535
+ * ```ts
536
+ * const results = await sdk.llm.vectors.query(queryVector, {
537
+ * topK: 5,
538
+ * filter: { documentId: 'doc-1' },
539
+ * workspaceId: 'ws-123'
540
+ * });
541
+ * ```
542
+ */
543
+ async query(vector, options = {}) {
544
+ const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/query`, {
545
+ method: "POST",
546
+ headers: this.headers,
547
+ body: JSON.stringify({
548
+ vector,
549
+ topK: options.topK ?? 5,
550
+ filter: options.filter,
551
+ workspaceId: options.workspaceId
552
+ })
553
+ });
554
+ const data = await response.json();
555
+ if (data.code === "PERMISSION_REQUIRED") {
556
+ throw new LLMPermissionError(data.permission || "vectors.read");
557
+ }
558
+ return data;
559
+ }
560
+ /**
561
+ * Delete vectors from storage
562
+ *
563
+ * Note: Currently only supports deleteAll: true
564
+ * Use workspaceId to scope deletion to a specific workspace
565
+ *
566
+ * @example
567
+ * ```ts
568
+ * await sdk.llm.vectors.delete({ deleteAll: true, workspaceId: 'ws-123' });
569
+ * ```
570
+ */
571
+ async delete(options) {
572
+ const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/delete`, {
573
+ method: "POST",
574
+ headers: this.headers,
575
+ body: JSON.stringify(options)
576
+ });
577
+ const data = await response.json();
578
+ if (data.code === "PERMISSION_REQUIRED") {
579
+ throw new LLMPermissionError(data.permission || "vectors.write");
580
+ }
581
+ return data;
582
+ }
583
+ /**
584
+ * List all available workspaces (namespaces) for this app
585
+ *
586
+ * @example
587
+ * ```ts
588
+ * const { workspaces } = await sdk.llm.vectors.listWorkspaces();
589
+ * console.log('Workspaces:', workspaces);
590
+ * ```
591
+ */
592
+ async listWorkspaces() {
593
+ const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/workspaces`, {
594
+ method: "GET",
595
+ headers: this.headers
596
+ });
597
+ const data = await response.json();
598
+ if (data.code === "PERMISSION_REQUIRED") {
599
+ throw new LLMPermissionError(data.permission || "vectors.read");
600
+ }
601
+ return data;
602
+ }
603
+ };
604
+ var LLMModule = class {
605
+ constructor(baseUrl, appId) {
606
+ this.baseUrl = baseUrl;
607
+ this.appId = appId;
608
+ this.vectors = new VectorStore(baseUrl, appId);
609
+ }
610
+ get headers() {
611
+ return {
612
+ "Content-Type": "application/json",
613
+ "x-app-id": this.appId
614
+ };
615
+ }
616
+ /**
617
+ * Get available LLM and embedding providers/models
618
+ *
619
+ * @example
620
+ * ```ts
621
+ * const { llm, embedding } = await sdk.llm.getProviders();
622
+ * console.log('Available LLM models:', llm[0].models);
623
+ * ```
624
+ */
625
+ async getProviders() {
626
+ const response = await fetch(`${this.baseUrl}/sdk/llm/providers`, {
627
+ method: "GET",
628
+ headers: this.headers
629
+ });
630
+ const data = await response.json();
631
+ if (data.code === "PERMISSION_REQUIRED") {
632
+ throw new LLMPermissionError(data.permission || "llm.providers");
633
+ }
634
+ return data;
635
+ }
636
+ /**
637
+ * Send a chat completion request (synchronous)
638
+ *
639
+ * @example
640
+ * ```ts
641
+ * const response = await sdk.llm.chat([
642
+ * { role: 'system', content: 'You are a helpful assistant.' },
643
+ * { role: 'user', content: 'Hello!' }
644
+ * ], { model: 'gpt-4o', temperature: 0.7 });
645
+ *
646
+ * console.log(response.response?.content);
647
+ * ```
648
+ */
649
+ async chat(messages, options = {}) {
650
+ const response = await fetch(`${this.baseUrl}/sdk/llm/chat`, {
651
+ method: "POST",
652
+ headers: this.headers,
653
+ body: JSON.stringify({
654
+ messages,
655
+ model: options.model,
656
+ provider: options.provider,
657
+ temperature: options.temperature ?? 0.7,
658
+ max_tokens: options.max_tokens ?? 1e3
659
+ })
660
+ });
661
+ const data = await response.json();
662
+ if (data.code === "PERMISSION_REQUIRED") {
663
+ throw new LLMPermissionError(data.permission || "llm.chat");
664
+ }
665
+ if (data.code === "LLM_ERROR") {
666
+ throw new LLMProviderError(data.error || "LLM request failed");
667
+ }
668
+ return data;
669
+ }
670
+ /**
671
+ * Send a streaming chat completion request (SSE)
672
+ *
673
+ * @example
674
+ * ```ts
675
+ * for await (const chunk of sdk.llm.chatStream([
676
+ * { role: 'user', content: 'Tell me a story' }
677
+ * ])) {
678
+ * process.stdout.write(chunk.textResponse || '');
679
+ * }
680
+ * ```
681
+ */
682
+ async *chatStream(messages, options = {}) {
683
+ const response = await fetch(`${this.baseUrl}/sdk/llm/chat/stream`, {
684
+ method: "POST",
685
+ headers: {
686
+ ...this.headers,
687
+ "Accept": "text/event-stream"
688
+ },
689
+ body: JSON.stringify({
690
+ messages,
691
+ model: options.model,
692
+ provider: options.provider,
693
+ temperature: options.temperature ?? 0.7,
694
+ max_tokens: options.max_tokens ?? 1e3
695
+ })
696
+ });
697
+ if (!response.ok) {
698
+ const errorData = await response.json();
699
+ if (errorData.code === "PERMISSION_REQUIRED") {
700
+ throw new LLMPermissionError(errorData.permission || "llm.chat");
701
+ }
702
+ throw new LLMProviderError(errorData.error || "Stream request failed");
703
+ }
704
+ const reader = response.body?.getReader();
705
+ if (!reader) {
706
+ throw new LLMProviderError("Response body is not readable");
707
+ }
708
+ const decoder = new TextDecoder();
709
+ let buffer = "";
710
+ let isErrorEvent = false;
711
+ try {
712
+ while (true) {
713
+ const { done, value } = await reader.read();
714
+ if (done) break;
715
+ buffer += decoder.decode(value, { stream: true });
716
+ const lines = buffer.split("\n");
717
+ buffer = lines.pop() || "";
718
+ for (const line of lines) {
719
+ const trimmedLine = line.trim();
720
+ if (!trimmedLine || trimmedLine.startsWith(":")) continue;
721
+ if (trimmedLine.startsWith("event: error")) {
722
+ isErrorEvent = true;
723
+ continue;
724
+ }
725
+ if (trimmedLine.startsWith("data: ")) {
726
+ const jsonStr = trimmedLine.slice(6);
727
+ if (jsonStr === "[DONE]") {
728
+ isErrorEvent = false;
729
+ continue;
730
+ }
731
+ try {
732
+ const data = JSON.parse(jsonStr);
733
+ if (isErrorEvent) {
734
+ isErrorEvent = false;
735
+ throw new LLMProviderError(
736
+ data.error || "Stream error",
737
+ data.code || "LLM_STREAM_ERROR"
738
+ );
739
+ }
740
+ const chunk = data;
741
+ if (chunk.error) {
742
+ throw new LLMProviderError(
743
+ chunk.message || "Stream error"
744
+ );
745
+ }
746
+ yield chunk;
747
+ } catch (parseError) {
748
+ isErrorEvent = false;
749
+ if (jsonStr !== "[DONE]") {
750
+ console.warn("[LLM Stream] Parse error:", jsonStr);
751
+ }
752
+ if (parseError instanceof LLMProviderError) throw parseError;
753
+ }
754
+ }
755
+ }
756
+ }
757
+ } finally {
758
+ reader.releaseLock();
759
+ }
760
+ }
761
+ /**
762
+ * Generate vector embeddings from text
763
+ *
764
+ * @example
765
+ * ```ts
766
+ * // Single text
767
+ * const { embeddings } = await sdk.llm.embed('Hello world');
768
+ *
769
+ * // Multiple texts
770
+ * const { embeddings } = await sdk.llm.embed(['Hello', 'World']);
771
+ * ```
772
+ */
773
+ async embed(input, options = {}) {
774
+ const inputArray = Array.isArray(input) ? input : [input];
775
+ const response = await fetch(`${this.baseUrl}/sdk/llm/embed`, {
776
+ method: "POST",
777
+ headers: this.headers,
778
+ body: JSON.stringify({
779
+ input: inputArray,
780
+ provider: options.provider,
781
+ model: options.model
782
+ })
783
+ });
784
+ const data = await response.json();
785
+ if (data.code === "PERMISSION_REQUIRED") {
786
+ throw new LLMPermissionError(data.permission || "llm.embed");
787
+ }
788
+ if (data.code === "PROVIDER_UNAVAILABLE") {
789
+ throw new LLMProviderError(data.error || "Embedding provider not available");
790
+ }
791
+ return data;
792
+ }
793
+ /**
794
+ * Helper: Embed text and store as vectors in one call
795
+ *
796
+ * @example
797
+ * ```ts
798
+ * await sdk.llm.embedAndStore({
799
+ * texts: ['Hello world', 'Goodbye world'],
800
+ * documentId: 'doc-123',
801
+ * workspaceId: 'ws-456'
802
+ * });
803
+ * ```
804
+ */
805
+ async embedAndStore(params) {
806
+ const { texts, documentId, workspaceId, idPrefix = "chunk", provider, model } = params;
807
+ const embedResult = await this.embed(texts, { provider, model });
808
+ if (!embedResult.success || !embedResult.embeddings) {
809
+ return {
810
+ success: false,
811
+ error: embedResult.error || "Embedding failed",
812
+ code: embedResult.code
813
+ };
814
+ }
815
+ const vectors = texts.map((text, i) => ({
816
+ id: `${idPrefix}_${i}`,
817
+ vector: embedResult.embeddings[i],
818
+ metadata: {
819
+ text,
820
+ documentId,
821
+ workspaceId
822
+ }
823
+ }));
824
+ return this.vectors.upsert(vectors, { workspaceId });
825
+ }
826
+ /**
827
+ * Helper: Search similar documents by text query
828
+ *
829
+ * @example
830
+ * ```ts
831
+ * const results = await sdk.llm.search('What is RealtimeX?', {
832
+ * topK: 5,
833
+ * workspaceId: 'ws-123'
834
+ * });
835
+ *
836
+ * for (const result of results) {
837
+ * console.log(result.metadata?.text, result.score);
838
+ * }
839
+ * ```
840
+ */
841
+ async search(query, options = {}) {
842
+ const embedResult = await this.embed(query, {
843
+ provider: options.provider,
844
+ model: options.model
845
+ });
846
+ if (!embedResult.success || !embedResult.embeddings?.[0]) {
847
+ throw new LLMProviderError("Failed to embed query");
848
+ }
849
+ const queryResult = await this.vectors.query(embedResult.embeddings[0], options);
850
+ if (!queryResult.success) {
851
+ throw new LLMProviderError(queryResult.error || "Vector search failed");
852
+ }
853
+ return queryResult.results || [];
854
+ }
855
+ };
856
+
475
857
  // src/index.ts
476
858
  var _RealtimeXSDK = class _RealtimeXSDK {
477
859
  constructor(config = {}) {
@@ -486,6 +868,7 @@ var _RealtimeXSDK = class _RealtimeXSDK {
486
868
  this.api = new ApiModule(this.realtimexUrl, this.appId, this.appName);
487
869
  this.task = new TaskModule(this.realtimexUrl, this.appName, this.appId);
488
870
  this.port = new PortModule(config.defaultPort);
871
+ this.llm = new LLMModule(this.realtimexUrl, this.appId);
489
872
  if (this.permissions.length > 0) {
490
873
  this.register().catch((err) => {
491
874
  console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
@@ -537,10 +920,14 @@ var RealtimeXSDK = _RealtimeXSDK;
537
920
  0 && (module.exports = {
538
921
  ActivitiesModule,
539
922
  ApiModule,
923
+ LLMModule,
924
+ LLMPermissionError,
925
+ LLMProviderError,
540
926
  PermissionDeniedError,
541
927
  PermissionRequiredError,
542
928
  PortModule,
543
929
  RealtimeXSDK,
544
930
  TaskModule,
931
+ VectorStore,
545
932
  WebhookModule
546
933
  });