@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/README.md +152 -0
- package/dist/index.d.mts +293 -1
- package/dist/index.d.ts +293 -1
- package/dist/index.js +387 -0
- package/dist/index.mjs +383 -0
- package/package.json +1 -1
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
|
});
|