@realtimex/sdk 1.1.2 → 1.1.3

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.d.mts CHANGED
@@ -150,14 +150,16 @@ declare class WebhookModule {
150
150
  */
151
151
  declare class PermissionDeniedError extends Error {
152
152
  readonly permission: string;
153
- constructor(permission: string, message?: string);
153
+ readonly code: string;
154
+ constructor(permission: string, message?: string, code?: string);
154
155
  }
155
156
  /**
156
157
  * Error thrown when a permission needs to be granted
157
158
  */
158
159
  declare class PermissionRequiredError extends Error {
159
160
  readonly permission: string;
160
- constructor(permission: string, message?: string);
161
+ readonly code: string;
162
+ constructor(permission: string, message?: string, code?: string);
161
163
  }
162
164
  declare class ApiModule {
163
165
  private realtimexUrl;
@@ -263,6 +265,7 @@ declare class PortModule {
263
265
  * - Provider/model listing
264
266
  * - Vector storage (upsert, query, delete)
265
267
  */
268
+
266
269
  interface ChatMessage {
267
270
  role: 'system' | 'user' | 'assistant';
268
271
  content: string;
@@ -272,6 +275,9 @@ interface ChatOptions {
272
275
  provider?: string;
273
276
  temperature?: number;
274
277
  max_tokens?: number;
278
+ response_format?: {
279
+ type: string;
280
+ };
275
281
  }
276
282
  interface ChatResponse {
277
283
  success: boolean;
@@ -391,9 +397,10 @@ interface VectorListWorkspacesResponse {
391
397
  error?: string;
392
398
  code?: string;
393
399
  }
394
- declare class LLMPermissionError extends Error {
395
- permission: string;
396
- code: string;
400
+ /**
401
+ * @deprecated Use PermissionRequiredError from api module instead
402
+ */
403
+ declare class LLMPermissionError extends PermissionRequiredError {
397
404
  constructor(permission: string, code?: string);
398
405
  }
399
406
  declare class LLMProviderError extends Error {
@@ -403,9 +410,18 @@ declare class LLMProviderError extends Error {
403
410
  declare class VectorStore {
404
411
  private baseUrl;
405
412
  private appId;
413
+ private appName;
406
414
  private apiKey?;
407
- constructor(baseUrl: string, appId: string, apiKey?: string | undefined);
415
+ constructor(baseUrl: string, appId: string, appName?: string, apiKey?: string | undefined);
408
416
  private get headers();
417
+ /**
418
+ * Request a single permission from Electron via internal API
419
+ */
420
+ private requestPermission;
421
+ /**
422
+ * Internal request wrapper that handles automatic permission prompts
423
+ */
424
+ private request;
409
425
  /**
410
426
  * Upsert (insert or update) vectors into storage
411
427
  *
@@ -456,10 +472,19 @@ declare class VectorStore {
456
472
  declare class LLMModule {
457
473
  private baseUrl;
458
474
  private appId;
475
+ private appName;
459
476
  private apiKey?;
460
477
  vectors: VectorStore;
461
- constructor(baseUrl: string, appId: string, apiKey?: string | undefined);
478
+ constructor(baseUrl: string, appId: string, appName?: string, apiKey?: string | undefined);
462
479
  private get headers();
480
+ /**
481
+ * Request a single permission from Electron via internal API
482
+ */
483
+ private requestPermission;
484
+ /**
485
+ * Internal request wrapper that handles automatic permission prompts
486
+ */
487
+ private request;
463
488
  /**
464
489
  * Get only configured chat (LLM) providers
465
490
  *
package/dist/index.d.ts CHANGED
@@ -150,14 +150,16 @@ declare class WebhookModule {
150
150
  */
151
151
  declare class PermissionDeniedError extends Error {
152
152
  readonly permission: string;
153
- constructor(permission: string, message?: string);
153
+ readonly code: string;
154
+ constructor(permission: string, message?: string, code?: string);
154
155
  }
155
156
  /**
156
157
  * Error thrown when a permission needs to be granted
157
158
  */
158
159
  declare class PermissionRequiredError extends Error {
159
160
  readonly permission: string;
160
- constructor(permission: string, message?: string);
161
+ readonly code: string;
162
+ constructor(permission: string, message?: string, code?: string);
161
163
  }
162
164
  declare class ApiModule {
163
165
  private realtimexUrl;
@@ -263,6 +265,7 @@ declare class PortModule {
263
265
  * - Provider/model listing
264
266
  * - Vector storage (upsert, query, delete)
265
267
  */
268
+
266
269
  interface ChatMessage {
267
270
  role: 'system' | 'user' | 'assistant';
268
271
  content: string;
@@ -272,6 +275,9 @@ interface ChatOptions {
272
275
  provider?: string;
273
276
  temperature?: number;
274
277
  max_tokens?: number;
278
+ response_format?: {
279
+ type: string;
280
+ };
275
281
  }
276
282
  interface ChatResponse {
277
283
  success: boolean;
@@ -391,9 +397,10 @@ interface VectorListWorkspacesResponse {
391
397
  error?: string;
392
398
  code?: string;
393
399
  }
394
- declare class LLMPermissionError extends Error {
395
- permission: string;
396
- code: string;
400
+ /**
401
+ * @deprecated Use PermissionRequiredError from api module instead
402
+ */
403
+ declare class LLMPermissionError extends PermissionRequiredError {
397
404
  constructor(permission: string, code?: string);
398
405
  }
399
406
  declare class LLMProviderError extends Error {
@@ -403,9 +410,18 @@ declare class LLMProviderError extends Error {
403
410
  declare class VectorStore {
404
411
  private baseUrl;
405
412
  private appId;
413
+ private appName;
406
414
  private apiKey?;
407
- constructor(baseUrl: string, appId: string, apiKey?: string | undefined);
415
+ constructor(baseUrl: string, appId: string, appName?: string, apiKey?: string | undefined);
408
416
  private get headers();
417
+ /**
418
+ * Request a single permission from Electron via internal API
419
+ */
420
+ private requestPermission;
421
+ /**
422
+ * Internal request wrapper that handles automatic permission prompts
423
+ */
424
+ private request;
409
425
  /**
410
426
  * Upsert (insert or update) vectors into storage
411
427
  *
@@ -456,10 +472,19 @@ declare class VectorStore {
456
472
  declare class LLMModule {
457
473
  private baseUrl;
458
474
  private appId;
475
+ private appName;
459
476
  private apiKey?;
460
477
  vectors: VectorStore;
461
- constructor(baseUrl: string, appId: string, apiKey?: string | undefined);
478
+ constructor(baseUrl: string, appId: string, appName?: string, apiKey?: string | undefined);
462
479
  private get headers();
480
+ /**
481
+ * Request a single permission from Electron via internal API
482
+ */
483
+ private requestPermission;
484
+ /**
485
+ * Internal request wrapper that handles automatic permission prompts
486
+ */
487
+ private request;
463
488
  /**
464
489
  * Get only configured chat (LLM) providers
465
490
  *
package/dist/index.js CHANGED
@@ -47,17 +47,19 @@ module.exports = __toCommonJS(index_exports);
47
47
 
48
48
  // src/modules/api.ts
49
49
  var PermissionDeniedError = class extends Error {
50
- constructor(permission, message) {
50
+ constructor(permission, message, code = "PERMISSION_DENIED") {
51
51
  super(message || `Permission '${permission}' was denied`);
52
52
  this.name = "PermissionDeniedError";
53
53
  this.permission = permission;
54
+ this.code = code;
54
55
  }
55
56
  };
56
57
  var PermissionRequiredError = class extends Error {
57
- constructor(permission, message) {
58
+ constructor(permission, message, code = "PERMISSION_REQUIRED") {
58
59
  super(message || `Permission '${permission}' is required`);
59
60
  this.name = "PermissionRequiredError";
60
61
  this.permission = permission;
62
+ this.code = code;
61
63
  }
62
64
  };
63
65
  var ApiModule = class {
@@ -501,11 +503,9 @@ var PortModule = class {
501
503
  };
502
504
 
503
505
  // src/modules/llm.ts
504
- var LLMPermissionError = class extends Error {
506
+ var LLMPermissionError = class extends PermissionRequiredError {
505
507
  constructor(permission, code = "PERMISSION_REQUIRED") {
506
- super(`Permission required: ${permission}`);
507
- this.permission = permission;
508
- this.code = code;
508
+ super(permission, void 0, code);
509
509
  this.name = "LLMPermissionError";
510
510
  }
511
511
  };
@@ -517,9 +517,10 @@ var LLMProviderError = class extends Error {
517
517
  }
518
518
  };
519
519
  var VectorStore = class {
520
- constructor(baseUrl, appId, apiKey) {
520
+ constructor(baseUrl, appId, appName = "Local App", apiKey) {
521
521
  this.baseUrl = baseUrl;
522
522
  this.appId = appId;
523
+ this.appName = appName;
523
524
  this.apiKey = apiKey;
524
525
  }
525
526
  get headers() {
@@ -534,6 +535,52 @@ var VectorStore = class {
534
535
  "x-app-id": this.appId
535
536
  };
536
537
  }
538
+ /**
539
+ * Request a single permission from Electron via internal API
540
+ */
541
+ async requestPermission(permission) {
542
+ try {
543
+ const response = await fetch(`${this.baseUrl}/api/local-apps/request-permission`, {
544
+ method: "POST",
545
+ headers: { "Content-Type": "application/json" },
546
+ body: JSON.stringify({
547
+ app_id: this.appId,
548
+ app_name: this.appName,
549
+ permission
550
+ })
551
+ });
552
+ const data = await response.json();
553
+ return data.granted === true;
554
+ } catch (error) {
555
+ return false;
556
+ }
557
+ }
558
+ /**
559
+ * Internal request wrapper that handles automatic permission prompts
560
+ */
561
+ async request(method, endpoint, body) {
562
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
563
+ method,
564
+ headers: this.headers,
565
+ body: body ? JSON.stringify(body) : void 0
566
+ });
567
+ const data = await response.json();
568
+ if (data.code === "PERMISSION_REQUIRED") {
569
+ const permission = data.permission || "vectors.read";
570
+ const granted = await this.requestPermission(permission);
571
+ if (granted) {
572
+ return this.request(method, endpoint, body);
573
+ }
574
+ throw new PermissionDeniedError(permission);
575
+ }
576
+ if (!data.success && data.error) {
577
+ if (data.code === "LLM_ERROR") {
578
+ throw new LLMProviderError(data.error);
579
+ }
580
+ throw new Error(data.error);
581
+ }
582
+ return data;
583
+ }
537
584
  /**
538
585
  * Upsert (insert or update) vectors into storage
539
586
  *
@@ -545,19 +592,10 @@ var VectorStore = class {
545
592
  * ```
546
593
  */
547
594
  async upsert(vectors, options = {}) {
548
- const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/upsert`, {
549
- method: "POST",
550
- headers: this.headers,
551
- body: JSON.stringify({
552
- vectors,
553
- workspaceId: options.workspaceId
554
- })
595
+ return this.request("POST", "/sdk/llm/vectors/upsert", {
596
+ vectors,
597
+ workspaceId: options.workspaceId
555
598
  });
556
- const data = await response.json();
557
- if (data.code === "PERMISSION_REQUIRED") {
558
- throw new LLMPermissionError(data.permission || "vectors.write");
559
- }
560
- return data;
561
599
  }
562
600
  /**
563
601
  * Query similar vectors by embedding
@@ -572,21 +610,12 @@ var VectorStore = class {
572
610
  * ```
573
611
  */
574
612
  async query(vector, options = {}) {
575
- const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/query`, {
576
- method: "POST",
577
- headers: this.headers,
578
- body: JSON.stringify({
579
- vector,
580
- topK: options.topK ?? 5,
581
- filter: options.filter,
582
- workspaceId: options.workspaceId
583
- })
613
+ return this.request("POST", "/sdk/llm/vectors/query", {
614
+ vector,
615
+ topK: options.topK ?? 5,
616
+ filter: options.filter,
617
+ workspaceId: options.workspaceId
584
618
  });
585
- const data = await response.json();
586
- if (data.code === "PERMISSION_REQUIRED") {
587
- throw new LLMPermissionError(data.permission || "vectors.read");
588
- }
589
- return data;
590
619
  }
591
620
  /**
592
621
  * Delete vectors from storage
@@ -600,16 +629,7 @@ var VectorStore = class {
600
629
  * ```
601
630
  */
602
631
  async delete(options) {
603
- const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/delete`, {
604
- method: "POST",
605
- headers: this.headers,
606
- body: JSON.stringify(options)
607
- });
608
- const data = await response.json();
609
- if (data.code === "PERMISSION_REQUIRED") {
610
- throw new LLMPermissionError(data.permission || "vectors.write");
611
- }
612
- return data;
632
+ return this.request("POST", "/sdk/llm/vectors/delete", options);
613
633
  }
614
634
  /**
615
635
  * List all available workspaces (namespaces) for this app
@@ -621,23 +641,16 @@ var VectorStore = class {
621
641
  * ```
622
642
  */
623
643
  async listWorkspaces() {
624
- const response = await fetch(`${this.baseUrl}/sdk/llm/vectors/workspaces`, {
625
- method: "GET",
626
- headers: this.headers
627
- });
628
- const data = await response.json();
629
- if (data.code === "PERMISSION_REQUIRED") {
630
- throw new LLMPermissionError(data.permission || "vectors.read");
631
- }
632
- return data;
644
+ return this.request("GET", "/sdk/llm/vectors/workspaces");
633
645
  }
634
646
  };
635
647
  var LLMModule = class {
636
- constructor(baseUrl, appId, apiKey) {
648
+ constructor(baseUrl, appId, appName = "Local App", apiKey) {
637
649
  this.baseUrl = baseUrl;
638
650
  this.appId = appId;
651
+ this.appName = appName;
639
652
  this.apiKey = apiKey;
640
- this.vectors = new VectorStore(baseUrl, appId, apiKey);
653
+ this.vectors = new VectorStore(baseUrl, appId, appName, apiKey);
641
654
  }
642
655
  get headers() {
643
656
  if (this.apiKey) {
@@ -651,6 +664,52 @@ var LLMModule = class {
651
664
  "x-app-id": this.appId
652
665
  };
653
666
  }
667
+ /**
668
+ * Request a single permission from Electron via internal API
669
+ */
670
+ async requestPermission(permission) {
671
+ try {
672
+ const response = await fetch(`${this.baseUrl}/api/local-apps/request-permission`, {
673
+ method: "POST",
674
+ headers: { "Content-Type": "application/json" },
675
+ body: JSON.stringify({
676
+ app_id: this.appId,
677
+ app_name: this.appName,
678
+ permission
679
+ })
680
+ });
681
+ const data = await response.json();
682
+ return data.granted === true;
683
+ } catch (error) {
684
+ return false;
685
+ }
686
+ }
687
+ /**
688
+ * Internal request wrapper that handles automatic permission prompts
689
+ */
690
+ async request(method, endpoint, body) {
691
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
692
+ method,
693
+ headers: this.headers,
694
+ body: body ? JSON.stringify(body) : void 0
695
+ });
696
+ const data = await response.json();
697
+ if (data.code === "PERMISSION_REQUIRED") {
698
+ const permission = data.permission || "llm.chat";
699
+ const granted = await this.requestPermission(permission);
700
+ if (granted) {
701
+ return this.request(method, endpoint, body);
702
+ }
703
+ throw new PermissionDeniedError(permission);
704
+ }
705
+ if (!data.success && data.error) {
706
+ if (data.code === "LLM_ERROR") {
707
+ throw new LLMProviderError(data.error);
708
+ }
709
+ throw new Error(data.error);
710
+ }
711
+ return data;
712
+ }
654
713
  /**
655
714
  * Get only configured chat (LLM) providers
656
715
  *
@@ -661,15 +720,7 @@ var LLMModule = class {
661
720
  * ```
662
721
  */
663
722
  async chatProviders() {
664
- const response = await fetch(`${this.baseUrl}/sdk/llm/providers/chat`, {
665
- method: "GET",
666
- headers: this.headers
667
- });
668
- const data = await response.json();
669
- if (data.code === "PERMISSION_REQUIRED") {
670
- throw new LLMPermissionError(data.permission || "llm.providers");
671
- }
672
- return data;
723
+ return this.request("GET", "/sdk/llm/providers/chat");
673
724
  }
674
725
  /**
675
726
  * Get only configured embedding providers
@@ -681,15 +732,7 @@ var LLMModule = class {
681
732
  * ```
682
733
  */
683
734
  async embedProviders() {
684
- const response = await fetch(`${this.baseUrl}/sdk/llm/providers/embed`, {
685
- method: "GET",
686
- headers: this.headers
687
- });
688
- const data = await response.json();
689
- if (data.code === "PERMISSION_REQUIRED") {
690
- throw new LLMPermissionError(data.permission || "llm.providers");
691
- }
692
- return data;
735
+ return this.request("GET", "/sdk/llm/providers/embed");
693
736
  }
694
737
  /**
695
738
  * Send a chat completion request (synchronous)
@@ -705,25 +748,14 @@ var LLMModule = class {
705
748
  * ```
706
749
  */
707
750
  async chat(messages, options = {}) {
708
- const response = await fetch(`${this.baseUrl}/sdk/llm/chat`, {
709
- method: "POST",
710
- headers: this.headers,
711
- body: JSON.stringify({
712
- messages,
713
- model: options.model,
714
- provider: options.provider,
715
- temperature: options.temperature ?? 0.7,
716
- max_tokens: options.max_tokens ?? 1e3
717
- })
751
+ return this.request("POST", "/sdk/llm/chat", {
752
+ messages,
753
+ model: options.model,
754
+ provider: options.provider,
755
+ temperature: options.temperature ?? 0.7,
756
+ max_tokens: options.max_tokens ?? 1e3,
757
+ response_format: options.response_format
718
758
  });
719
- const data = await response.json();
720
- if (data.code === "PERMISSION_REQUIRED") {
721
- throw new LLMPermissionError(data.permission || "llm.chat");
722
- }
723
- if (data.code === "LLM_ERROR") {
724
- throw new LLMProviderError(data.error || "LLM request failed");
725
- }
726
- return data;
727
759
  }
728
760
  /**
729
761
  * Send a streaming chat completion request (SSE)
@@ -749,13 +781,20 @@ var LLMModule = class {
749
781
  model: options.model,
750
782
  provider: options.provider,
751
783
  temperature: options.temperature ?? 0.7,
752
- max_tokens: options.max_tokens ?? 1e3
784
+ max_tokens: options.max_tokens ?? 1e3,
785
+ response_format: options.response_format
753
786
  })
754
787
  });
755
788
  if (!response.ok) {
756
789
  const errorData = await response.json();
757
790
  if (errorData.code === "PERMISSION_REQUIRED") {
758
- throw new LLMPermissionError(errorData.permission || "llm.chat");
791
+ const permission = errorData.permission || "llm.chat";
792
+ const granted = await this.requestPermission(permission);
793
+ if (granted) {
794
+ yield* this.chatStream(messages, options);
795
+ return;
796
+ }
797
+ throw new PermissionDeniedError(permission);
759
798
  }
760
799
  throw new LLMProviderError(errorData.error || "Stream request failed");
761
800
  }
@@ -830,23 +869,11 @@ var LLMModule = class {
830
869
  */
831
870
  async embed(input, options = {}) {
832
871
  const inputArray = Array.isArray(input) ? input : [input];
833
- const response = await fetch(`${this.baseUrl}/sdk/llm/embed`, {
834
- method: "POST",
835
- headers: this.headers,
836
- body: JSON.stringify({
837
- input: inputArray,
838
- provider: options.provider,
839
- model: options.model
840
- })
872
+ return this.request("POST", "/sdk/llm/embed", {
873
+ input: inputArray,
874
+ provider: options.provider,
875
+ model: options.model
841
876
  });
842
- const data = await response.json();
843
- if (data.code === "PERMISSION_REQUIRED") {
844
- throw new LLMPermissionError(data.permission || "llm.embed");
845
- }
846
- if (data.code === "PROVIDER_UNAVAILABLE") {
847
- throw new LLMProviderError(data.error || "Embedding provider not available");
848
- }
849
- return data;
850
877
  }
851
878
  /**
852
879
  * Helper: Embed text and store as vectors in one call
@@ -937,7 +964,7 @@ var _RealtimeXSDK = class _RealtimeXSDK {
937
964
  this.api = new ApiModule(this.realtimexUrl, this.appId, this.appName, this.apiKey);
938
965
  this.task = new TaskModule(this.realtimexUrl, this.appName, this.appId, this.apiKey);
939
966
  this.port = new PortModule(config.defaultPort);
940
- this.llm = new LLMModule(this.realtimexUrl, this.appId, this.apiKey);
967
+ this.llm = new LLMModule(this.realtimexUrl, this.appId, this.appName, this.apiKey);
941
968
  if (this.permissions.length > 0 && this.appId && !this.apiKey) {
942
969
  this.register().catch((err) => {
943
970
  console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
package/dist/index.mjs CHANGED
@@ -1,16 +1,18 @@
1
1
  // src/modules/api.ts
2
2
  var PermissionDeniedError = class extends Error {
3
- constructor(permission, message) {
3
+ constructor(permission, message, code = "PERMISSION_DENIED") {
4
4
  super(message || `Permission '${permission}' was denied`);
5
5
  this.name = "PermissionDeniedError";
6
6
  this.permission = permission;
7
+ this.code = code;
7
8
  }
8
9
  };
9
10
  var PermissionRequiredError = class extends Error {
10
- constructor(permission, message) {
11
+ constructor(permission, message, code = "PERMISSION_REQUIRED") {
11
12
  super(message || `Permission '${permission}' is required`);
12
13
  this.name = "PermissionRequiredError";
13
14
  this.permission = permission;
15
+ this.code = code;
14
16
  }
15
17
  };
16
18
  var ApiModule = class {
@@ -454,11 +456,9 @@ var PortModule = class {
454
456
  };
455
457
 
456
458
  // src/modules/llm.ts
457
- var LLMPermissionError = class extends Error {
459
+ var LLMPermissionError = class extends PermissionRequiredError {
458
460
  constructor(permission, code = "PERMISSION_REQUIRED") {
459
- super(`Permission required: ${permission}`);
460
- this.permission = permission;
461
- this.code = code;
461
+ super(permission, void 0, code);
462
462
  this.name = "LLMPermissionError";
463
463
  }
464
464
  };
@@ -470,9 +470,10 @@ var LLMProviderError = class extends Error {
470
470
  }
471
471
  };
472
472
  var VectorStore = class {
473
- constructor(baseUrl, appId, apiKey) {
473
+ constructor(baseUrl, appId, appName = "Local App", apiKey) {
474
474
  this.baseUrl = baseUrl;
475
475
  this.appId = appId;
476
+ this.appName = appName;
476
477
  this.apiKey = apiKey;
477
478
  }
478
479
  get headers() {
@@ -487,6 +488,52 @@ var VectorStore = class {
487
488
  "x-app-id": this.appId
488
489
  };
489
490
  }
491
+ /**
492
+ * Request a single permission from Electron via internal API
493
+ */
494
+ async requestPermission(permission) {
495
+ try {
496
+ const response = await fetch(`${this.baseUrl}/api/local-apps/request-permission`, {
497
+ method: "POST",
498
+ headers: { "Content-Type": "application/json" },
499
+ body: JSON.stringify({
500
+ app_id: this.appId,
501
+ app_name: this.appName,
502
+ permission
503
+ })
504
+ });
505
+ const data = await response.json();
506
+ return data.granted === true;
507
+ } catch (error) {
508
+ return false;
509
+ }
510
+ }
511
+ /**
512
+ * Internal request wrapper that handles automatic permission prompts
513
+ */
514
+ async request(method, endpoint, body) {
515
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
516
+ method,
517
+ headers: this.headers,
518
+ body: body ? JSON.stringify(body) : void 0
519
+ });
520
+ const data = await response.json();
521
+ if (data.code === "PERMISSION_REQUIRED") {
522
+ const permission = data.permission || "vectors.read";
523
+ const granted = await this.requestPermission(permission);
524
+ if (granted) {
525
+ return this.request(method, endpoint, body);
526
+ }
527
+ throw new PermissionDeniedError(permission);
528
+ }
529
+ if (!data.success && data.error) {
530
+ if (data.code === "LLM_ERROR") {
531
+ throw new LLMProviderError(data.error);
532
+ }
533
+ throw new Error(data.error);
534
+ }
535
+ return data;
536
+ }
490
537
  /**
491
538
  * Upsert (insert or update) vectors into storage
492
539
  *
@@ -498,19 +545,10 @@ var VectorStore = class {
498
545
  * ```
499
546
  */
500
547
  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
- })
548
+ return this.request("POST", "/sdk/llm/vectors/upsert", {
549
+ vectors,
550
+ workspaceId: options.workspaceId
508
551
  });
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
552
  }
515
553
  /**
516
554
  * Query similar vectors by embedding
@@ -525,21 +563,12 @@ var VectorStore = class {
525
563
  * ```
526
564
  */
527
565
  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
- })
566
+ return this.request("POST", "/sdk/llm/vectors/query", {
567
+ vector,
568
+ topK: options.topK ?? 5,
569
+ filter: options.filter,
570
+ workspaceId: options.workspaceId
537
571
  });
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
572
  }
544
573
  /**
545
574
  * Delete vectors from storage
@@ -553,16 +582,7 @@ var VectorStore = class {
553
582
  * ```
554
583
  */
555
584
  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;
585
+ return this.request("POST", "/sdk/llm/vectors/delete", options);
566
586
  }
567
587
  /**
568
588
  * List all available workspaces (namespaces) for this app
@@ -574,23 +594,16 @@ var VectorStore = class {
574
594
  * ```
575
595
  */
576
596
  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;
597
+ return this.request("GET", "/sdk/llm/vectors/workspaces");
586
598
  }
587
599
  };
588
600
  var LLMModule = class {
589
- constructor(baseUrl, appId, apiKey) {
601
+ constructor(baseUrl, appId, appName = "Local App", apiKey) {
590
602
  this.baseUrl = baseUrl;
591
603
  this.appId = appId;
604
+ this.appName = appName;
592
605
  this.apiKey = apiKey;
593
- this.vectors = new VectorStore(baseUrl, appId, apiKey);
606
+ this.vectors = new VectorStore(baseUrl, appId, appName, apiKey);
594
607
  }
595
608
  get headers() {
596
609
  if (this.apiKey) {
@@ -604,6 +617,52 @@ var LLMModule = class {
604
617
  "x-app-id": this.appId
605
618
  };
606
619
  }
620
+ /**
621
+ * Request a single permission from Electron via internal API
622
+ */
623
+ async requestPermission(permission) {
624
+ try {
625
+ const response = await fetch(`${this.baseUrl}/api/local-apps/request-permission`, {
626
+ method: "POST",
627
+ headers: { "Content-Type": "application/json" },
628
+ body: JSON.stringify({
629
+ app_id: this.appId,
630
+ app_name: this.appName,
631
+ permission
632
+ })
633
+ });
634
+ const data = await response.json();
635
+ return data.granted === true;
636
+ } catch (error) {
637
+ return false;
638
+ }
639
+ }
640
+ /**
641
+ * Internal request wrapper that handles automatic permission prompts
642
+ */
643
+ async request(method, endpoint, body) {
644
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
645
+ method,
646
+ headers: this.headers,
647
+ body: body ? JSON.stringify(body) : void 0
648
+ });
649
+ const data = await response.json();
650
+ if (data.code === "PERMISSION_REQUIRED") {
651
+ const permission = data.permission || "llm.chat";
652
+ const granted = await this.requestPermission(permission);
653
+ if (granted) {
654
+ return this.request(method, endpoint, body);
655
+ }
656
+ throw new PermissionDeniedError(permission);
657
+ }
658
+ if (!data.success && data.error) {
659
+ if (data.code === "LLM_ERROR") {
660
+ throw new LLMProviderError(data.error);
661
+ }
662
+ throw new Error(data.error);
663
+ }
664
+ return data;
665
+ }
607
666
  /**
608
667
  * Get only configured chat (LLM) providers
609
668
  *
@@ -614,15 +673,7 @@ var LLMModule = class {
614
673
  * ```
615
674
  */
616
675
  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;
676
+ return this.request("GET", "/sdk/llm/providers/chat");
626
677
  }
627
678
  /**
628
679
  * Get only configured embedding providers
@@ -634,15 +685,7 @@ var LLMModule = class {
634
685
  * ```
635
686
  */
636
687
  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;
688
+ return this.request("GET", "/sdk/llm/providers/embed");
646
689
  }
647
690
  /**
648
691
  * Send a chat completion request (synchronous)
@@ -658,25 +701,14 @@ var LLMModule = class {
658
701
  * ```
659
702
  */
660
703
  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
- })
704
+ return this.request("POST", "/sdk/llm/chat", {
705
+ messages,
706
+ model: options.model,
707
+ provider: options.provider,
708
+ temperature: options.temperature ?? 0.7,
709
+ max_tokens: options.max_tokens ?? 1e3,
710
+ response_format: options.response_format
671
711
  });
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
712
  }
681
713
  /**
682
714
  * Send a streaming chat completion request (SSE)
@@ -702,13 +734,20 @@ var LLMModule = class {
702
734
  model: options.model,
703
735
  provider: options.provider,
704
736
  temperature: options.temperature ?? 0.7,
705
- max_tokens: options.max_tokens ?? 1e3
737
+ max_tokens: options.max_tokens ?? 1e3,
738
+ response_format: options.response_format
706
739
  })
707
740
  });
708
741
  if (!response.ok) {
709
742
  const errorData = await response.json();
710
743
  if (errorData.code === "PERMISSION_REQUIRED") {
711
- throw new LLMPermissionError(errorData.permission || "llm.chat");
744
+ const permission = errorData.permission || "llm.chat";
745
+ const granted = await this.requestPermission(permission);
746
+ if (granted) {
747
+ yield* this.chatStream(messages, options);
748
+ return;
749
+ }
750
+ throw new PermissionDeniedError(permission);
712
751
  }
713
752
  throw new LLMProviderError(errorData.error || "Stream request failed");
714
753
  }
@@ -783,23 +822,11 @@ var LLMModule = class {
783
822
  */
784
823
  async embed(input, options = {}) {
785
824
  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
- })
825
+ return this.request("POST", "/sdk/llm/embed", {
826
+ input: inputArray,
827
+ provider: options.provider,
828
+ model: options.model
794
829
  });
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
830
  }
804
831
  /**
805
832
  * Helper: Embed text and store as vectors in one call
@@ -890,7 +917,7 @@ var _RealtimeXSDK = class _RealtimeXSDK {
890
917
  this.api = new ApiModule(this.realtimexUrl, this.appId, this.appName, this.apiKey);
891
918
  this.task = new TaskModule(this.realtimexUrl, this.appName, this.appId, this.apiKey);
892
919
  this.port = new PortModule(config.defaultPort);
893
- this.llm = new LLMModule(this.realtimexUrl, this.appId, this.apiKey);
920
+ this.llm = new LLMModule(this.realtimexUrl, this.appId, this.appName, this.apiKey);
894
921
  if (this.permissions.length > 0 && this.appId && !this.apiKey) {
895
922
  this.register().catch((err) => {
896
923
  console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@realtimex/sdk",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "SDK for building Local Apps that integrate with RealtimeX",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",