@realtimex/sdk 1.0.9 → 1.1.2
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 +165 -2
- package/dist/index.d.mts +326 -5
- package/dist/index.d.ts +326 -5
- package/dist/index.js +497 -16
- package/dist/index.mjs +493 -16
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -14,12 +14,19 @@ var PermissionRequiredError = class extends Error {
|
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
16
|
var ApiModule = class {
|
|
17
|
-
constructor(realtimexUrl, appId, appName) {
|
|
17
|
+
constructor(realtimexUrl, appId, appName, apiKey) {
|
|
18
18
|
this.realtimexUrl = realtimexUrl.replace(/\/$/, "");
|
|
19
19
|
this.appId = appId;
|
|
20
20
|
this.appName = appName || process.env.RTX_APP_NAME || "Local App";
|
|
21
|
+
this.apiKey = apiKey;
|
|
21
22
|
}
|
|
22
23
|
getHeaders() {
|
|
24
|
+
if (this.apiKey) {
|
|
25
|
+
return {
|
|
26
|
+
"Content-Type": "application/json",
|
|
27
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
28
|
+
};
|
|
29
|
+
}
|
|
23
30
|
return {
|
|
24
31
|
"Content-Type": "application/json",
|
|
25
32
|
"x-app-id": this.appId
|
|
@@ -98,10 +105,11 @@ var ApiModule = class {
|
|
|
98
105
|
|
|
99
106
|
// src/modules/activities.ts
|
|
100
107
|
var ActivitiesModule = class {
|
|
101
|
-
constructor(realtimexUrl, appId, appName) {
|
|
108
|
+
constructor(realtimexUrl, appId, appName, apiKey) {
|
|
102
109
|
this.baseUrl = realtimexUrl.replace(/\/$/, "");
|
|
103
110
|
this.appId = appId;
|
|
104
111
|
this.appName = appName || process.env.RTX_APP_NAME || "Local App";
|
|
112
|
+
this.apiKey = apiKey;
|
|
105
113
|
}
|
|
106
114
|
/**
|
|
107
115
|
* Request a single permission from Electron via internal API
|
|
@@ -129,8 +137,10 @@ var ActivitiesModule = class {
|
|
|
129
137
|
const headers = {
|
|
130
138
|
"Content-Type": "application/json"
|
|
131
139
|
};
|
|
132
|
-
if (this.
|
|
133
|
-
headers["
|
|
140
|
+
if (this.apiKey) {
|
|
141
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
142
|
+
} else if (this.appId) {
|
|
143
|
+
headers["x-app-id"] = this.appId;
|
|
134
144
|
}
|
|
135
145
|
const response = await fetch(url, {
|
|
136
146
|
...options,
|
|
@@ -217,10 +227,11 @@ var ActivitiesModule = class {
|
|
|
217
227
|
|
|
218
228
|
// src/modules/webhook.ts
|
|
219
229
|
var WebhookModule = class {
|
|
220
|
-
constructor(realtimexUrl, appName, appId) {
|
|
230
|
+
constructor(realtimexUrl, appName, appId, apiKey) {
|
|
221
231
|
this.realtimexUrl = realtimexUrl.replace(/\/$/, "");
|
|
222
232
|
this.appName = appName;
|
|
223
233
|
this.appId = appId;
|
|
234
|
+
this.apiKey = apiKey;
|
|
224
235
|
}
|
|
225
236
|
/**
|
|
226
237
|
* Request a single permission from Electron via internal API
|
|
@@ -245,12 +256,18 @@ var WebhookModule = class {
|
|
|
245
256
|
}
|
|
246
257
|
async request(path, options = {}) {
|
|
247
258
|
const url = `${this.realtimexUrl}${path}`;
|
|
259
|
+
const headers = {
|
|
260
|
+
"Content-Type": "application/json",
|
|
261
|
+
...options.headers
|
|
262
|
+
};
|
|
263
|
+
if (this.apiKey) {
|
|
264
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
265
|
+
} else if (this.appId) {
|
|
266
|
+
headers["x-app-id"] = this.appId;
|
|
267
|
+
}
|
|
248
268
|
const response = await fetch(url, {
|
|
249
269
|
...options,
|
|
250
|
-
headers
|
|
251
|
-
"Content-Type": "application/json",
|
|
252
|
-
...options.headers
|
|
253
|
-
}
|
|
270
|
+
headers
|
|
254
271
|
});
|
|
255
272
|
const data = await response.json();
|
|
256
273
|
if (response.status === 403) {
|
|
@@ -309,10 +326,11 @@ var WebhookModule = class {
|
|
|
309
326
|
|
|
310
327
|
// src/modules/task.ts
|
|
311
328
|
var TaskModule = class {
|
|
312
|
-
constructor(realtimexUrl, appName, appId) {
|
|
329
|
+
constructor(realtimexUrl, appName, appId, apiKey) {
|
|
313
330
|
this.realtimexUrl = realtimexUrl.replace(/\/$/, "");
|
|
314
331
|
this.appName = appName;
|
|
315
332
|
this.appId = appId;
|
|
333
|
+
this.apiKey = apiKey;
|
|
316
334
|
}
|
|
317
335
|
/**
|
|
318
336
|
* Mark task as processing
|
|
@@ -333,9 +351,15 @@ var TaskModule = class {
|
|
|
333
351
|
return this._sendEvent("task-fail", taskUuid, { error, machine_id: machineId });
|
|
334
352
|
}
|
|
335
353
|
async _sendEvent(event, taskUuid, extra) {
|
|
354
|
+
const headers = { "Content-Type": "application/json" };
|
|
355
|
+
if (this.apiKey) {
|
|
356
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
357
|
+
} else if (this.appId) {
|
|
358
|
+
headers["x-app-id"] = this.appId;
|
|
359
|
+
}
|
|
336
360
|
const response = await fetch(`${this.realtimexUrl}/webhooks/realtimex`, {
|
|
337
361
|
method: "POST",
|
|
338
|
-
headers
|
|
362
|
+
headers,
|
|
339
363
|
body: JSON.stringify({
|
|
340
364
|
app_name: this.appName,
|
|
341
365
|
app_id: this.appId,
|
|
@@ -429,21 +453,445 @@ var PortModule = class {
|
|
|
429
453
|
}
|
|
430
454
|
};
|
|
431
455
|
|
|
456
|
+
// src/modules/llm.ts
|
|
457
|
+
var LLMPermissionError = class extends Error {
|
|
458
|
+
constructor(permission, code = "PERMISSION_REQUIRED") {
|
|
459
|
+
super(`Permission required: ${permission}`);
|
|
460
|
+
this.permission = permission;
|
|
461
|
+
this.code = code;
|
|
462
|
+
this.name = "LLMPermissionError";
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
var LLMProviderError = class extends Error {
|
|
466
|
+
constructor(message, code = "LLM_ERROR") {
|
|
467
|
+
super(message);
|
|
468
|
+
this.code = code;
|
|
469
|
+
this.name = "LLMProviderError";
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
var VectorStore = class {
|
|
473
|
+
constructor(baseUrl, appId, apiKey) {
|
|
474
|
+
this.baseUrl = baseUrl;
|
|
475
|
+
this.appId = appId;
|
|
476
|
+
this.apiKey = apiKey;
|
|
477
|
+
}
|
|
478
|
+
get headers() {
|
|
479
|
+
if (this.apiKey) {
|
|
480
|
+
return {
|
|
481
|
+
"Content-Type": "application/json",
|
|
482
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
return {
|
|
486
|
+
"Content-Type": "application/json",
|
|
487
|
+
"x-app-id": this.appId
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Upsert (insert or update) vectors into storage
|
|
492
|
+
*
|
|
493
|
+
* @example
|
|
494
|
+
* ```ts
|
|
495
|
+
* await sdk.llm.vectors.upsert([
|
|
496
|
+
* { id: 'chunk-1', vector: embeddings[0], metadata: { text: 'Hello', documentId: 'doc-1' } }
|
|
497
|
+
* ], { workspaceId: 'ws-123' });
|
|
498
|
+
* ```
|
|
499
|
+
*/
|
|
500
|
+
async upsert(vectors, options = {}) {
|
|
501
|
+
const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/upsert`, {
|
|
502
|
+
method: "POST",
|
|
503
|
+
headers: this.headers,
|
|
504
|
+
body: JSON.stringify({
|
|
505
|
+
vectors,
|
|
506
|
+
workspaceId: options.workspaceId
|
|
507
|
+
})
|
|
508
|
+
});
|
|
509
|
+
const data = await response.json();
|
|
510
|
+
if (data.code === "PERMISSION_REQUIRED") {
|
|
511
|
+
throw new LLMPermissionError(data.permission || "vectors.write");
|
|
512
|
+
}
|
|
513
|
+
return data;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Query similar vectors by embedding
|
|
517
|
+
*
|
|
518
|
+
* @example
|
|
519
|
+
* ```ts
|
|
520
|
+
* const results = await sdk.llm.vectors.query(queryVector, {
|
|
521
|
+
* topK: 5,
|
|
522
|
+
* filter: { documentId: 'doc-1' },
|
|
523
|
+
* workspaceId: 'ws-123'
|
|
524
|
+
* });
|
|
525
|
+
* ```
|
|
526
|
+
*/
|
|
527
|
+
async query(vector, options = {}) {
|
|
528
|
+
const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/query`, {
|
|
529
|
+
method: "POST",
|
|
530
|
+
headers: this.headers,
|
|
531
|
+
body: JSON.stringify({
|
|
532
|
+
vector,
|
|
533
|
+
topK: options.topK ?? 5,
|
|
534
|
+
filter: options.filter,
|
|
535
|
+
workspaceId: options.workspaceId
|
|
536
|
+
})
|
|
537
|
+
});
|
|
538
|
+
const data = await response.json();
|
|
539
|
+
if (data.code === "PERMISSION_REQUIRED") {
|
|
540
|
+
throw new LLMPermissionError(data.permission || "vectors.read");
|
|
541
|
+
}
|
|
542
|
+
return data;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Delete vectors from storage
|
|
546
|
+
*
|
|
547
|
+
* Note: Currently only supports deleteAll: true
|
|
548
|
+
* Use workspaceId to scope deletion to a specific workspace
|
|
549
|
+
*
|
|
550
|
+
* @example
|
|
551
|
+
* ```ts
|
|
552
|
+
* await sdk.llm.vectors.delete({ deleteAll: true, workspaceId: 'ws-123' });
|
|
553
|
+
* ```
|
|
554
|
+
*/
|
|
555
|
+
async delete(options) {
|
|
556
|
+
const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/delete`, {
|
|
557
|
+
method: "POST",
|
|
558
|
+
headers: this.headers,
|
|
559
|
+
body: JSON.stringify(options)
|
|
560
|
+
});
|
|
561
|
+
const data = await response.json();
|
|
562
|
+
if (data.code === "PERMISSION_REQUIRED") {
|
|
563
|
+
throw new LLMPermissionError(data.permission || "vectors.write");
|
|
564
|
+
}
|
|
565
|
+
return data;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* List all available workspaces (namespaces) for this app
|
|
569
|
+
*
|
|
570
|
+
* @example
|
|
571
|
+
* ```ts
|
|
572
|
+
* const { workspaces } = await sdk.llm.vectors.listWorkspaces();
|
|
573
|
+
* console.log('Workspaces:', workspaces);
|
|
574
|
+
* ```
|
|
575
|
+
*/
|
|
576
|
+
async listWorkspaces() {
|
|
577
|
+
const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/workspaces`, {
|
|
578
|
+
method: "GET",
|
|
579
|
+
headers: this.headers
|
|
580
|
+
});
|
|
581
|
+
const data = await response.json();
|
|
582
|
+
if (data.code === "PERMISSION_REQUIRED") {
|
|
583
|
+
throw new LLMPermissionError(data.permission || "vectors.read");
|
|
584
|
+
}
|
|
585
|
+
return data;
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
var LLMModule = class {
|
|
589
|
+
constructor(baseUrl, appId, apiKey) {
|
|
590
|
+
this.baseUrl = baseUrl;
|
|
591
|
+
this.appId = appId;
|
|
592
|
+
this.apiKey = apiKey;
|
|
593
|
+
this.vectors = new VectorStore(baseUrl, appId, apiKey);
|
|
594
|
+
}
|
|
595
|
+
get headers() {
|
|
596
|
+
if (this.apiKey) {
|
|
597
|
+
return {
|
|
598
|
+
"Content-Type": "application/json",
|
|
599
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
return {
|
|
603
|
+
"Content-Type": "application/json",
|
|
604
|
+
"x-app-id": this.appId
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Get only configured chat (LLM) providers
|
|
609
|
+
*
|
|
610
|
+
* @example
|
|
611
|
+
* ```ts
|
|
612
|
+
* const { providers } = await sdk.llm.chatProviders();
|
|
613
|
+
* console.log('Available chat models:', providers[0].models);
|
|
614
|
+
* ```
|
|
615
|
+
*/
|
|
616
|
+
async chatProviders() {
|
|
617
|
+
const response = await fetch(`${this.baseUrl}/sdk/llm/providers/chat`, {
|
|
618
|
+
method: "GET",
|
|
619
|
+
headers: this.headers
|
|
620
|
+
});
|
|
621
|
+
const data = await response.json();
|
|
622
|
+
if (data.code === "PERMISSION_REQUIRED") {
|
|
623
|
+
throw new LLMPermissionError(data.permission || "llm.providers");
|
|
624
|
+
}
|
|
625
|
+
return data;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Get only configured embedding providers
|
|
629
|
+
*
|
|
630
|
+
* @example
|
|
631
|
+
* ```ts
|
|
632
|
+
* const { providers } = await sdk.llm.embedProviders();
|
|
633
|
+
* console.log('Available embedding models:', providers[0].models);
|
|
634
|
+
* ```
|
|
635
|
+
*/
|
|
636
|
+
async embedProviders() {
|
|
637
|
+
const response = await fetch(`${this.baseUrl}/sdk/llm/providers/embed`, {
|
|
638
|
+
method: "GET",
|
|
639
|
+
headers: this.headers
|
|
640
|
+
});
|
|
641
|
+
const data = await response.json();
|
|
642
|
+
if (data.code === "PERMISSION_REQUIRED") {
|
|
643
|
+
throw new LLMPermissionError(data.permission || "llm.providers");
|
|
644
|
+
}
|
|
645
|
+
return data;
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Send a chat completion request (synchronous)
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* ```ts
|
|
652
|
+
* const response = await sdk.llm.chat([
|
|
653
|
+
* { role: 'system', content: 'You are a helpful assistant.' },
|
|
654
|
+
* { role: 'user', content: 'Hello!' }
|
|
655
|
+
* ], { model: 'gpt-4o', temperature: 0.7 });
|
|
656
|
+
*
|
|
657
|
+
* console.log(response.response?.content);
|
|
658
|
+
* ```
|
|
659
|
+
*/
|
|
660
|
+
async chat(messages, options = {}) {
|
|
661
|
+
const response = await fetch(`${this.baseUrl}/sdk/llm/chat`, {
|
|
662
|
+
method: "POST",
|
|
663
|
+
headers: this.headers,
|
|
664
|
+
body: JSON.stringify({
|
|
665
|
+
messages,
|
|
666
|
+
model: options.model,
|
|
667
|
+
provider: options.provider,
|
|
668
|
+
temperature: options.temperature ?? 0.7,
|
|
669
|
+
max_tokens: options.max_tokens ?? 1e3
|
|
670
|
+
})
|
|
671
|
+
});
|
|
672
|
+
const data = await response.json();
|
|
673
|
+
if (data.code === "PERMISSION_REQUIRED") {
|
|
674
|
+
throw new LLMPermissionError(data.permission || "llm.chat");
|
|
675
|
+
}
|
|
676
|
+
if (data.code === "LLM_ERROR") {
|
|
677
|
+
throw new LLMProviderError(data.error || "LLM request failed");
|
|
678
|
+
}
|
|
679
|
+
return data;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Send a streaming chat completion request (SSE)
|
|
683
|
+
*
|
|
684
|
+
* @example
|
|
685
|
+
* ```ts
|
|
686
|
+
* for await (const chunk of sdk.llm.chatStream([
|
|
687
|
+
* { role: 'user', content: 'Tell me a story' }
|
|
688
|
+
* ])) {
|
|
689
|
+
* process.stdout.write(chunk.textResponse || '');
|
|
690
|
+
* }
|
|
691
|
+
* ```
|
|
692
|
+
*/
|
|
693
|
+
async *chatStream(messages, options = {}) {
|
|
694
|
+
const response = await fetch(`${this.baseUrl}/sdk/llm/chat/stream`, {
|
|
695
|
+
method: "POST",
|
|
696
|
+
headers: {
|
|
697
|
+
...this.headers,
|
|
698
|
+
"Accept": "text/event-stream"
|
|
699
|
+
},
|
|
700
|
+
body: JSON.stringify({
|
|
701
|
+
messages,
|
|
702
|
+
model: options.model,
|
|
703
|
+
provider: options.provider,
|
|
704
|
+
temperature: options.temperature ?? 0.7,
|
|
705
|
+
max_tokens: options.max_tokens ?? 1e3
|
|
706
|
+
})
|
|
707
|
+
});
|
|
708
|
+
if (!response.ok) {
|
|
709
|
+
const errorData = await response.json();
|
|
710
|
+
if (errorData.code === "PERMISSION_REQUIRED") {
|
|
711
|
+
throw new LLMPermissionError(errorData.permission || "llm.chat");
|
|
712
|
+
}
|
|
713
|
+
throw new LLMProviderError(errorData.error || "Stream request failed");
|
|
714
|
+
}
|
|
715
|
+
const reader = response.body?.getReader();
|
|
716
|
+
if (!reader) {
|
|
717
|
+
throw new LLMProviderError("Response body is not readable");
|
|
718
|
+
}
|
|
719
|
+
const decoder = new TextDecoder();
|
|
720
|
+
let buffer = "";
|
|
721
|
+
let isErrorEvent = false;
|
|
722
|
+
try {
|
|
723
|
+
while (true) {
|
|
724
|
+
const { done, value } = await reader.read();
|
|
725
|
+
if (done) break;
|
|
726
|
+
buffer += decoder.decode(value, { stream: true });
|
|
727
|
+
const lines = buffer.split("\n");
|
|
728
|
+
buffer = lines.pop() || "";
|
|
729
|
+
for (const line of lines) {
|
|
730
|
+
const trimmedLine = line.trim();
|
|
731
|
+
if (!trimmedLine || trimmedLine.startsWith(":")) continue;
|
|
732
|
+
if (trimmedLine.startsWith("event: error")) {
|
|
733
|
+
isErrorEvent = true;
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
if (trimmedLine.startsWith("data: ")) {
|
|
737
|
+
const jsonStr = trimmedLine.slice(6);
|
|
738
|
+
if (jsonStr === "[DONE]") {
|
|
739
|
+
isErrorEvent = false;
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
try {
|
|
743
|
+
const data = JSON.parse(jsonStr);
|
|
744
|
+
if (isErrorEvent) {
|
|
745
|
+
isErrorEvent = false;
|
|
746
|
+
throw new LLMProviderError(
|
|
747
|
+
data.error || "Stream error",
|
|
748
|
+
data.code || "LLM_STREAM_ERROR"
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
const chunk = data;
|
|
752
|
+
if (chunk.error) {
|
|
753
|
+
throw new LLMProviderError(
|
|
754
|
+
chunk.message || "Stream error"
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
yield chunk;
|
|
758
|
+
} catch (parseError) {
|
|
759
|
+
isErrorEvent = false;
|
|
760
|
+
if (jsonStr !== "[DONE]") {
|
|
761
|
+
console.warn("[LLM Stream] Parse error:", jsonStr);
|
|
762
|
+
}
|
|
763
|
+
if (parseError instanceof LLMProviderError) throw parseError;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
} finally {
|
|
769
|
+
reader.releaseLock();
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Generate vector embeddings from text
|
|
774
|
+
*
|
|
775
|
+
* @example
|
|
776
|
+
* ```ts
|
|
777
|
+
* // Single text
|
|
778
|
+
* const { embeddings } = await sdk.llm.embed('Hello world');
|
|
779
|
+
*
|
|
780
|
+
* // Multiple texts
|
|
781
|
+
* const { embeddings } = await sdk.llm.embed(['Hello', 'World']);
|
|
782
|
+
* ```
|
|
783
|
+
*/
|
|
784
|
+
async embed(input, options = {}) {
|
|
785
|
+
const inputArray = Array.isArray(input) ? input : [input];
|
|
786
|
+
const response = await fetch(`${this.baseUrl}/sdk/llm/embed`, {
|
|
787
|
+
method: "POST",
|
|
788
|
+
headers: this.headers,
|
|
789
|
+
body: JSON.stringify({
|
|
790
|
+
input: inputArray,
|
|
791
|
+
provider: options.provider,
|
|
792
|
+
model: options.model
|
|
793
|
+
})
|
|
794
|
+
});
|
|
795
|
+
const data = await response.json();
|
|
796
|
+
if (data.code === "PERMISSION_REQUIRED") {
|
|
797
|
+
throw new LLMPermissionError(data.permission || "llm.embed");
|
|
798
|
+
}
|
|
799
|
+
if (data.code === "PROVIDER_UNAVAILABLE") {
|
|
800
|
+
throw new LLMProviderError(data.error || "Embedding provider not available");
|
|
801
|
+
}
|
|
802
|
+
return data;
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Helper: Embed text and store as vectors in one call
|
|
806
|
+
*
|
|
807
|
+
* @example
|
|
808
|
+
* ```ts
|
|
809
|
+
* await sdk.llm.embedAndStore({
|
|
810
|
+
* texts: ['Hello world', 'Goodbye world'],
|
|
811
|
+
* documentId: 'doc-123',
|
|
812
|
+
* workspaceId: 'ws-456'
|
|
813
|
+
* });
|
|
814
|
+
* ```
|
|
815
|
+
*/
|
|
816
|
+
async embedAndStore(params) {
|
|
817
|
+
const { texts, documentId, workspaceId, idPrefix = "chunk", provider, model } = params;
|
|
818
|
+
const embedResult = await this.embed(texts, { provider, model });
|
|
819
|
+
if (!embedResult.success || !embedResult.embeddings) {
|
|
820
|
+
return {
|
|
821
|
+
success: false,
|
|
822
|
+
error: embedResult.error || "Embedding failed",
|
|
823
|
+
code: embedResult.code
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
let uniquePrefix = idPrefix;
|
|
827
|
+
if (idPrefix === "chunk") {
|
|
828
|
+
const randomSuffix = Math.random().toString(36).substring(2, 6);
|
|
829
|
+
uniquePrefix = `chunk_${randomSuffix}`;
|
|
830
|
+
}
|
|
831
|
+
const vectors = texts.map((text, i) => ({
|
|
832
|
+
id: `${uniquePrefix}_${i}`,
|
|
833
|
+
vector: embedResult.embeddings[i],
|
|
834
|
+
metadata: {
|
|
835
|
+
text,
|
|
836
|
+
documentId,
|
|
837
|
+
workspaceId,
|
|
838
|
+
embeddingModel: embedResult.model || model || "unknown"
|
|
839
|
+
}
|
|
840
|
+
}));
|
|
841
|
+
return this.vectors.upsert(vectors, { workspaceId });
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Helper: Search similar documents by text query
|
|
845
|
+
*
|
|
846
|
+
* @example
|
|
847
|
+
* ```ts
|
|
848
|
+
* const results = await sdk.llm.search('What is RealtimeX?', {
|
|
849
|
+
* topK: 5,
|
|
850
|
+
* workspaceId: 'ws-123'
|
|
851
|
+
* });
|
|
852
|
+
*
|
|
853
|
+
* for (const result of results) {
|
|
854
|
+
* console.log(result.metadata?.text, result.score);
|
|
855
|
+
* }
|
|
856
|
+
* ```
|
|
857
|
+
*/
|
|
858
|
+
async search(query, options = {}) {
|
|
859
|
+
const embedResult = await this.embed(query, {
|
|
860
|
+
provider: options.provider,
|
|
861
|
+
model: options.model
|
|
862
|
+
});
|
|
863
|
+
if (!embedResult.success || !embedResult.embeddings?.[0]) {
|
|
864
|
+
throw new LLMProviderError("Failed to embed query");
|
|
865
|
+
}
|
|
866
|
+
const queryResult = await this.vectors.query(embedResult.embeddings[0], {
|
|
867
|
+
...options,
|
|
868
|
+
model: options.model || embedResult.model
|
|
869
|
+
});
|
|
870
|
+
if (!queryResult.success) {
|
|
871
|
+
throw new LLMProviderError(queryResult.error || "Vector search failed");
|
|
872
|
+
}
|
|
873
|
+
return queryResult.results || [];
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
|
|
432
877
|
// src/index.ts
|
|
433
878
|
var _RealtimeXSDK = class _RealtimeXSDK {
|
|
434
879
|
constructor(config = {}) {
|
|
435
880
|
const envAppId = this.getEnvVar("RTX_APP_ID");
|
|
436
881
|
const envAppName = this.getEnvVar("RTX_APP_NAME");
|
|
882
|
+
const envApiKey = this.getEnvVar("RTX_API_KEY");
|
|
437
883
|
this.appId = config.realtimex?.appId || envAppId || "";
|
|
438
884
|
this.appName = config.realtimex?.appName || envAppName;
|
|
885
|
+
this.apiKey = config.realtimex?.apiKey || envApiKey;
|
|
439
886
|
this.permissions = config.permissions || [];
|
|
440
887
|
this.realtimexUrl = config.realtimex?.url || _RealtimeXSDK.DEFAULT_REALTIMEX_URL;
|
|
441
|
-
this.activities = new ActivitiesModule(this.realtimexUrl, this.appId, this.appName);
|
|
442
|
-
this.webhook = new WebhookModule(this.realtimexUrl, this.appName, this.appId);
|
|
443
|
-
this.api = new ApiModule(this.realtimexUrl, this.appId, this.appName);
|
|
444
|
-
this.task = new TaskModule(this.realtimexUrl, this.appName, this.appId);
|
|
888
|
+
this.activities = new ActivitiesModule(this.realtimexUrl, this.appId, this.appName, this.apiKey);
|
|
889
|
+
this.webhook = new WebhookModule(this.realtimexUrl, this.appName, this.appId, this.apiKey);
|
|
890
|
+
this.api = new ApiModule(this.realtimexUrl, this.appId, this.appName, this.apiKey);
|
|
891
|
+
this.task = new TaskModule(this.realtimexUrl, this.appName, this.appId, this.apiKey);
|
|
445
892
|
this.port = new PortModule(config.defaultPort);
|
|
446
|
-
|
|
893
|
+
this.llm = new LLMModule(this.realtimexUrl, this.appId, this.apiKey);
|
|
894
|
+
if (this.permissions.length > 0 && this.appId && !this.apiKey) {
|
|
447
895
|
this.register().catch((err) => {
|
|
448
896
|
console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
|
|
449
897
|
});
|
|
@@ -487,16 +935,45 @@ var _RealtimeXSDK = class _RealtimeXSDK {
|
|
|
487
935
|
}
|
|
488
936
|
return void 0;
|
|
489
937
|
}
|
|
938
|
+
/**
|
|
939
|
+
* Ping RealtimeX server to verify connection and authentication.
|
|
940
|
+
* Works in both development (API Key) and production (App ID) modes.
|
|
941
|
+
*/
|
|
942
|
+
async ping() {
|
|
943
|
+
try {
|
|
944
|
+
const headers = { "Content-Type": "application/json" };
|
|
945
|
+
if (this.apiKey) {
|
|
946
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
947
|
+
} else if (this.appId) {
|
|
948
|
+
headers["x-app-id"] = this.appId;
|
|
949
|
+
}
|
|
950
|
+
const response = await fetch(`${this.realtimexUrl.replace(/\/$/, "")}/sdk/ping`, {
|
|
951
|
+
method: "GET",
|
|
952
|
+
headers
|
|
953
|
+
});
|
|
954
|
+
const data = await response.json();
|
|
955
|
+
if (!response.ok) {
|
|
956
|
+
throw new Error(data.error || "Ping failed");
|
|
957
|
+
}
|
|
958
|
+
return data;
|
|
959
|
+
} catch (error) {
|
|
960
|
+
throw new Error(`Connection failed: ${error.message}`);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
490
963
|
};
|
|
491
964
|
_RealtimeXSDK.DEFAULT_REALTIMEX_URL = "http://localhost:3001";
|
|
492
965
|
var RealtimeXSDK = _RealtimeXSDK;
|
|
493
966
|
export {
|
|
494
967
|
ActivitiesModule,
|
|
495
968
|
ApiModule,
|
|
969
|
+
LLMModule,
|
|
970
|
+
LLMPermissionError,
|
|
971
|
+
LLMProviderError,
|
|
496
972
|
PermissionDeniedError,
|
|
497
973
|
PermissionRequiredError,
|
|
498
974
|
PortModule,
|
|
499
975
|
RealtimeXSDK,
|
|
500
976
|
TaskModule,
|
|
977
|
+
VectorStore,
|
|
501
978
|
WebhookModule
|
|
502
979
|
};
|