@realtimex/sdk 1.0.8 → 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,18 +32,144 @@ 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,
38
+ PermissionDeniedError: () => PermissionDeniedError,
39
+ PermissionRequiredError: () => PermissionRequiredError,
35
40
  PortModule: () => PortModule,
36
41
  RealtimeXSDK: () => RealtimeXSDK,
37
42
  TaskModule: () => TaskModule,
43
+ VectorStore: () => VectorStore,
38
44
  WebhookModule: () => WebhookModule
39
45
  });
40
46
  module.exports = __toCommonJS(index_exports);
41
47
 
48
+ // src/modules/api.ts
49
+ var PermissionDeniedError = class extends Error {
50
+ constructor(permission, message) {
51
+ super(message || `Permission '${permission}' was denied`);
52
+ this.name = "PermissionDeniedError";
53
+ this.permission = permission;
54
+ }
55
+ };
56
+ var PermissionRequiredError = class extends Error {
57
+ constructor(permission, message) {
58
+ super(message || `Permission '${permission}' is required`);
59
+ this.name = "PermissionRequiredError";
60
+ this.permission = permission;
61
+ }
62
+ };
63
+ var ApiModule = class {
64
+ constructor(realtimexUrl, appId, appName) {
65
+ this.realtimexUrl = realtimexUrl.replace(/\/$/, "");
66
+ this.appId = appId;
67
+ this.appName = appName || process.env.RTX_APP_NAME || "Local App";
68
+ }
69
+ getHeaders() {
70
+ return {
71
+ "Content-Type": "application/json",
72
+ "x-app-id": this.appId
73
+ };
74
+ }
75
+ /**
76
+ * Request a single permission from Electron via internal API
77
+ */
78
+ async requestPermission(permission) {
79
+ try {
80
+ const response = await fetch(`${this.realtimexUrl}/api/local-apps/request-permission`, {
81
+ method: "POST",
82
+ headers: { "Content-Type": "application/json" },
83
+ body: JSON.stringify({
84
+ app_id: this.appId,
85
+ app_name: this.appName,
86
+ permission
87
+ })
88
+ });
89
+ const data = await response.json();
90
+ return data.granted === true;
91
+ } catch (error) {
92
+ return false;
93
+ }
94
+ }
95
+ /**
96
+ * Make an API call with automatic permission handling
97
+ */
98
+ async apiCall(method, endpoint, options) {
99
+ const url = `${this.realtimexUrl}${endpoint}`;
100
+ const response = await fetch(url, {
101
+ method,
102
+ headers: this.getHeaders(),
103
+ ...options
104
+ });
105
+ const data = await response.json();
106
+ if (response.status === 403) {
107
+ const errorCode = data.error;
108
+ const permission = data.permission;
109
+ const message = data.message;
110
+ if (errorCode === "PERMISSION_REQUIRED" && permission) {
111
+ const granted = await this.requestPermission(permission);
112
+ if (granted) {
113
+ return this.apiCall(method, endpoint, options);
114
+ } else {
115
+ throw new PermissionDeniedError(permission, message);
116
+ }
117
+ }
118
+ if (errorCode === "PERMISSION_DENIED") {
119
+ throw new PermissionDeniedError(permission, message);
120
+ }
121
+ throw new Error(data.error || "Permission denied");
122
+ }
123
+ if (!response.ok) {
124
+ throw new Error(data.error || `API call failed: ${response.status}`);
125
+ }
126
+ return data;
127
+ }
128
+ async getAgents() {
129
+ const data = await this.apiCall("GET", "/agents");
130
+ return data.agents;
131
+ }
132
+ async getWorkspaces() {
133
+ const data = await this.apiCall("GET", "/workspaces");
134
+ return data.workspaces;
135
+ }
136
+ async getThreads(workspaceSlug) {
137
+ const data = await this.apiCall("GET", `/workspaces/${encodeURIComponent(workspaceSlug)}/threads`);
138
+ return data.threads;
139
+ }
140
+ async getTask(taskUuid) {
141
+ const data = await this.apiCall("GET", `/task/${encodeURIComponent(taskUuid)}`);
142
+ return { ...data.task, runs: data.runs };
143
+ }
144
+ };
145
+
42
146
  // src/modules/activities.ts
43
147
  var ActivitiesModule = class {
44
- constructor(realtimexUrl, appId) {
148
+ constructor(realtimexUrl, appId, appName) {
45
149
  this.baseUrl = realtimexUrl.replace(/\/$/, "");
46
150
  this.appId = appId;
151
+ this.appName = appName || process.env.RTX_APP_NAME || "Local App";
152
+ }
153
+ /**
154
+ * Request a single permission from Electron via internal API
155
+ */
156
+ async requestPermission(permission) {
157
+ try {
158
+ const response = await fetch(`${this.baseUrl}/api/local-apps/request-permission`, {
159
+ method: "POST",
160
+ headers: { "Content-Type": "application/json" },
161
+ body: JSON.stringify({
162
+ app_id: this.appId,
163
+ app_name: this.appName,
164
+ permission
165
+ })
166
+ });
167
+ const data = await response.json();
168
+ return data.granted === true;
169
+ } catch (error) {
170
+ console.error("[SDK] Permission request failed:", error);
171
+ return false;
172
+ }
47
173
  }
48
174
  async request(path, options = {}) {
49
175
  const url = `${this.baseUrl}${path}`;
@@ -61,6 +187,22 @@ var ActivitiesModule = class {
61
187
  }
62
188
  });
63
189
  const data = await response.json();
190
+ if (response.status === 403) {
191
+ const errorCode = data.error;
192
+ const permission = data.permission;
193
+ const message = data.message;
194
+ if (errorCode === "PERMISSION_REQUIRED" && permission) {
195
+ const granted = await this.requestPermission(permission);
196
+ if (granted) {
197
+ return this.request(path, options);
198
+ } else {
199
+ throw new PermissionDeniedError(permission, message);
200
+ }
201
+ }
202
+ if (errorCode === "PERMISSION_DENIED") {
203
+ throw new PermissionDeniedError(permission, message);
204
+ }
205
+ }
64
206
  if (!response.ok) {
65
207
  throw new Error(data.error || `Request failed: ${response.status}`);
66
208
  }
@@ -127,13 +269,64 @@ var WebhookModule = class {
127
269
  this.appName = appName;
128
270
  this.appId = appId;
129
271
  }
272
+ /**
273
+ * Request a single permission from Electron via internal API
274
+ */
275
+ async requestPermission(permission) {
276
+ try {
277
+ const response = await fetch(`${this.realtimexUrl}/api/local-apps/request-permission`, {
278
+ method: "POST",
279
+ headers: { "Content-Type": "application/json" },
280
+ body: JSON.stringify({
281
+ app_id: this.appId,
282
+ app_name: this.appName,
283
+ permission
284
+ })
285
+ });
286
+ const data = await response.json();
287
+ return data.granted === true;
288
+ } catch (error) {
289
+ console.error("[SDK] Permission request failed:", error);
290
+ return false;
291
+ }
292
+ }
293
+ async request(path, options = {}) {
294
+ const url = `${this.realtimexUrl}${path}`;
295
+ const response = await fetch(url, {
296
+ ...options,
297
+ headers: {
298
+ "Content-Type": "application/json",
299
+ ...options.headers
300
+ }
301
+ });
302
+ const data = await response.json();
303
+ if (response.status === 403) {
304
+ const errorCode = data.error;
305
+ const permission = data.permission;
306
+ const message = data.message;
307
+ if (errorCode === "PERMISSION_REQUIRED" && permission) {
308
+ const granted = await this.requestPermission(permission);
309
+ if (granted) {
310
+ return this.request(path, options);
311
+ } else {
312
+ throw new PermissionDeniedError(permission, message);
313
+ }
314
+ }
315
+ if (errorCode === "PERMISSION_DENIED") {
316
+ throw new PermissionDeniedError(permission, message);
317
+ }
318
+ }
319
+ if (!response.ok) {
320
+ throw new Error(data.error || `Request failed: ${response.status}`);
321
+ }
322
+ return data;
323
+ }
130
324
  async triggerAgent(payload) {
131
325
  if (payload.auto_run && (!payload.agent_name || !payload.workspace_slug)) {
132
326
  throw new Error("auto_run requires agent_name and workspace_slug");
133
327
  }
134
- const response = await fetch(`${this.realtimexUrl}/webhooks/realtimex`, {
328
+ return this.request("/webhooks/realtimex", {
135
329
  method: "POST",
136
- headers: { "Content-Type": "application/json" },
137
330
  body: JSON.stringify({
138
331
  app_name: this.appName,
139
332
  app_id: this.appId,
@@ -148,69 +341,16 @@ var WebhookModule = class {
148
341
  }
149
342
  })
150
343
  });
151
- const data = await response.json();
152
- if (!response.ok) throw new Error(data.error || "Failed to trigger agent");
153
- return data;
154
344
  }
155
345
  async ping() {
156
- const response = await fetch(`${this.realtimexUrl}/webhooks/realtimex`, {
346
+ return this.request("/webhooks/realtimex", {
157
347
  method: "POST",
158
- headers: { "Content-Type": "application/json" },
159
348
  body: JSON.stringify({
160
349
  app_name: this.appName,
161
350
  app_id: this.appId,
162
351
  event: "ping"
163
352
  })
164
353
  });
165
- const data = await response.json();
166
- if (!response.ok) throw new Error(data.error || "Ping failed");
167
- return data;
168
- }
169
- };
170
-
171
- // src/modules/api.ts
172
- var ApiModule = class {
173
- constructor(realtimexUrl, appId) {
174
- this.realtimexUrl = realtimexUrl.replace(/\/$/, "");
175
- this.appId = appId;
176
- }
177
- getHeaders() {
178
- return {
179
- "Content-Type": "application/json",
180
- "x-app-id": this.appId
181
- };
182
- }
183
- async getAgents() {
184
- const response = await fetch(`${this.realtimexUrl}/agents`, {
185
- headers: this.getHeaders()
186
- });
187
- const data = await response.json();
188
- if (!response.ok) throw new Error(data.error || "Failed to get agents");
189
- return data.agents;
190
- }
191
- async getWorkspaces() {
192
- const response = await fetch(`${this.realtimexUrl}/workspaces`, {
193
- headers: this.getHeaders()
194
- });
195
- const data = await response.json();
196
- if (!response.ok) throw new Error(data.error || "Failed to get workspaces");
197
- return data.workspaces;
198
- }
199
- async getThreads(workspaceSlug) {
200
- const response = await fetch(`${this.realtimexUrl}/workspaces/${encodeURIComponent(workspaceSlug)}/threads`, {
201
- headers: this.getHeaders()
202
- });
203
- const data = await response.json();
204
- if (!response.ok) throw new Error(data.error || "Failed to get threads");
205
- return data.threads;
206
- }
207
- async getTask(taskUuid) {
208
- const response = await fetch(`${this.realtimexUrl}/task/${encodeURIComponent(taskUuid)}`, {
209
- headers: this.getHeaders()
210
- });
211
- const data = await response.json();
212
- if (!response.ok) throw new Error(data.error || "Failed to get task");
213
- return { ...data.task, runs: data.runs };
214
354
  }
215
355
  };
216
356
 
@@ -336,6 +476,384 @@ var PortModule = class {
336
476
  }
337
477
  };
338
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
+
339
857
  // src/index.ts
340
858
  var _RealtimeXSDK = class _RealtimeXSDK {
341
859
  constructor(config = {}) {
@@ -343,12 +861,45 @@ var _RealtimeXSDK = class _RealtimeXSDK {
343
861
  const envAppName = this.getEnvVar("RTX_APP_NAME");
344
862
  this.appId = config.realtimex?.appId || envAppId || "";
345
863
  this.appName = config.realtimex?.appName || envAppName;
346
- const realtimexUrl = config.realtimex?.url || _RealtimeXSDK.DEFAULT_REALTIMEX_URL;
347
- this.activities = new ActivitiesModule(realtimexUrl, this.appId);
348
- this.webhook = new WebhookModule(realtimexUrl, this.appName, this.appId);
349
- this.api = new ApiModule(realtimexUrl, this.appId);
350
- this.task = new TaskModule(realtimexUrl, this.appName, this.appId);
864
+ this.permissions = config.permissions || [];
865
+ this.realtimexUrl = config.realtimex?.url || _RealtimeXSDK.DEFAULT_REALTIMEX_URL;
866
+ this.activities = new ActivitiesModule(this.realtimexUrl, this.appId, this.appName);
867
+ this.webhook = new WebhookModule(this.realtimexUrl, this.appName, this.appId);
868
+ this.api = new ApiModule(this.realtimexUrl, this.appId, this.appName);
869
+ this.task = new TaskModule(this.realtimexUrl, this.appName, this.appId);
351
870
  this.port = new PortModule(config.defaultPort);
871
+ this.llm = new LLMModule(this.realtimexUrl, this.appId);
872
+ if (this.permissions.length > 0) {
873
+ this.register().catch((err) => {
874
+ console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
875
+ });
876
+ }
877
+ }
878
+ /**
879
+ * Register app with RealtimeX hub and request declared permissions upfront.
880
+ * This is called automatically if permissions are provided in constructor.
881
+ */
882
+ async register(permissions) {
883
+ const perms = permissions || this.permissions;
884
+ if (perms.length === 0) return;
885
+ try {
886
+ const response = await fetch(`${this.realtimexUrl.replace(/\/$/, "")}/sdk/register`, {
887
+ method: "POST",
888
+ headers: { "Content-Type": "application/json" },
889
+ body: JSON.stringify({
890
+ app_id: this.appId,
891
+ app_name: this.appName,
892
+ permissions: perms
893
+ })
894
+ });
895
+ const data = await response.json();
896
+ if (!response.ok) {
897
+ throw new Error(data.error || "Registration failed");
898
+ }
899
+ console.log(`[RealtimeX SDK] App registered successfully (${data.message})`);
900
+ } catch (error) {
901
+ throw new Error(`Failed to register app: ${error.message}`);
902
+ }
352
903
  }
353
904
  /**
354
905
  * Get environment variable (works in Node.js and browser)
@@ -369,8 +920,14 @@ var RealtimeXSDK = _RealtimeXSDK;
369
920
  0 && (module.exports = {
370
921
  ActivitiesModule,
371
922
  ApiModule,
923
+ LLMModule,
924
+ LLMPermissionError,
925
+ LLMProviderError,
926
+ PermissionDeniedError,
927
+ PermissionRequiredError,
372
928
  PortModule,
373
929
  RealtimeXSDK,
374
930
  TaskModule,
931
+ VectorStore,
375
932
  WebhookModule
376
933
  });