voice-page-agent 2.7.4 → 2.7.6

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.cts CHANGED
@@ -9,11 +9,15 @@ type VoicePageAgentState = {
9
9
  micPermissionGranted: boolean;
10
10
  };
11
11
  type RuntimePageAgent = {
12
- panel: {
12
+ panel?: {
13
13
  show: () => void;
14
14
  expand: () => void;
15
+ hide?: () => void;
16
+ collapse?: () => void;
15
17
  };
16
18
  execute: (task: string) => Promise<unknown>;
19
+ dispose?: (...args: unknown[]) => void;
20
+ disposed?: boolean;
17
21
  status?: "idle" | "running" | "completed" | "error" | string;
18
22
  };
19
23
  type VoicePageAgentButtonTextOptions = {
@@ -84,6 +88,7 @@ declare class VoicePageAgentController {
84
88
  };
85
89
  onStateChange(listener: VoiceStateListener): () => void;
86
90
  openAgent(): Promise<RuntimePageAgent | null>;
91
+ toggleAgentPanel(): Promise<void>;
87
92
  startWake(): Promise<void>;
88
93
  stopWake(): void;
89
94
  runCommand(commandText: string): Promise<void>;
@@ -102,6 +107,9 @@ declare class VoicePageAgentController {
102
107
  private requestMicrophonePermission;
103
108
  private syncPermissionState;
104
109
  private ensureAgent;
110
+ private isAgentPanelVisible;
111
+ private hideAgentPanel;
112
+ private resolveAgentInitErrorMessage;
105
113
  private executeVoiceCommand;
106
114
  private buildRecognition;
107
115
  }
package/dist/index.d.ts CHANGED
@@ -9,11 +9,15 @@ type VoicePageAgentState = {
9
9
  micPermissionGranted: boolean;
10
10
  };
11
11
  type RuntimePageAgent = {
12
- panel: {
12
+ panel?: {
13
13
  show: () => void;
14
14
  expand: () => void;
15
+ hide?: () => void;
16
+ collapse?: () => void;
15
17
  };
16
18
  execute: (task: string) => Promise<unknown>;
19
+ dispose?: (...args: unknown[]) => void;
20
+ disposed?: boolean;
17
21
  status?: "idle" | "running" | "completed" | "error" | string;
18
22
  };
19
23
  type VoicePageAgentButtonTextOptions = {
@@ -84,6 +88,7 @@ declare class VoicePageAgentController {
84
88
  };
85
89
  onStateChange(listener: VoiceStateListener): () => void;
86
90
  openAgent(): Promise<RuntimePageAgent | null>;
91
+ toggleAgentPanel(): Promise<void>;
87
92
  startWake(): Promise<void>;
88
93
  stopWake(): void;
89
94
  runCommand(commandText: string): Promise<void>;
@@ -102,6 +107,9 @@ declare class VoicePageAgentController {
102
107
  private requestMicrophonePermission;
103
108
  private syncPermissionState;
104
109
  private ensureAgent;
110
+ private isAgentPanelVisible;
111
+ private hideAgentPanel;
112
+ private resolveAgentInitErrorMessage;
105
113
  private executeVoiceCommand;
106
114
  private buildRecognition;
107
115
  }
package/dist/index.js CHANGED
@@ -131,6 +131,14 @@ var VoicePageAgentController = class {
131
131
  async openAgent() {
132
132
  return this.ensureAgent();
133
133
  }
134
+ async toggleAgentPanel() {
135
+ if (typeof window === "undefined") return;
136
+ if (this.isAgentPanelVisible()) {
137
+ this.hideAgentPanel();
138
+ return;
139
+ }
140
+ await this.openAgent();
141
+ }
134
142
  async startWake() {
135
143
  if (this.disposed) return;
136
144
  if (!this.hasSpeechSupport()) {
@@ -313,26 +321,55 @@ var VoicePageAgentController = class {
313
321
  }
314
322
  }
315
323
  async ensureAgent() {
324
+ var _a;
316
325
  if (typeof window === "undefined") return null;
317
326
  const runtimeWindow = window;
318
- if (runtimeWindow.pageAgent) {
319
- runtimeWindow.pageAgent.panel.show();
320
- runtimeWindow.pageAgent.panel.expand();
321
- return runtimeWindow.pageAgent;
327
+ const existingAgent = runtimeWindow.pageAgent;
328
+ if (existingAgent) {
329
+ const panelNode = document.getElementById("page-agent-runtime_agent-panel");
330
+ const canReuse = Boolean(existingAgent.panel && (panelNode == null ? void 0 : panelNode.isConnected) && !existingAgent.disposed);
331
+ if (canReuse && existingAgent.panel) {
332
+ existingAgent.panel.show();
333
+ existingAgent.panel.expand();
334
+ return existingAgent;
335
+ }
336
+ try {
337
+ (_a = existingAgent.dispose) == null ? void 0 : _a.call(existingAgent, "RECREATE_WITH_PANEL");
338
+ } catch {
339
+ }
340
+ runtimeWindow.pageAgent = void 0;
322
341
  }
323
342
  if (this.initAgentPromise) return this.initAgentPromise;
324
343
  this.initAgentPromise = (async () => {
325
- const mod = await import('./page-agent-H32WE3CG.js');
344
+ const mod = await import('./page-agent-ZROQ54L4.js');
326
345
  const Agent = mod.PageAgent;
327
- const agent = new Agent(this.options.pageAgent);
346
+ let agent;
347
+ try {
348
+ agent = new Agent(this.options.pageAgent);
349
+ } catch (err) {
350
+ const message = err instanceof Error ? err.message : String(err || "");
351
+ const webglUnavailable = /webgl2 is required/i.test(message) || /webgl/i.test(message);
352
+ if (!webglUnavailable) {
353
+ throw err;
354
+ }
355
+ const fallbackConfig = {
356
+ ...this.options.pageAgent,
357
+ enableMask: false
358
+ };
359
+ agent = new Agent(fallbackConfig);
360
+ }
328
361
  runtimeWindow.pageAgent = agent;
362
+ if (!agent.panel) {
363
+ throw new Error("Page Agent panel is disabled. Set pageAgent.enablePanel=true.");
364
+ }
329
365
  agent.panel.show();
330
366
  agent.panel.expand();
331
367
  return agent;
332
368
  })().catch((err) => {
369
+ console.error("[voice-page-agent] ensureAgent failed:", err);
333
370
  this.patchState({
334
371
  status: "error",
335
- message: err instanceof Error ? err.message : "Page Agent \u521D\u59CB\u5316\u5931\u8D25"
372
+ message: this.resolveAgentInitErrorMessage(err)
336
373
  });
337
374
  return null;
338
375
  }).finally(() => {
@@ -340,6 +377,33 @@ var VoicePageAgentController = class {
340
377
  });
341
378
  return this.initAgentPromise;
342
379
  }
380
+ isAgentPanelVisible() {
381
+ const panelNode = document.getElementById("page-agent-runtime_agent-panel");
382
+ if (!panelNode) return false;
383
+ const style = window.getComputedStyle(panelNode);
384
+ return style.display !== "none" && style.visibility !== "hidden" && style.opacity !== "0";
385
+ }
386
+ hideAgentPanel() {
387
+ var _a, _b, _c, _d;
388
+ const runtimeWindow = window;
389
+ const agent = runtimeWindow.pageAgent;
390
+ if (agent == null ? void 0 : agent.panel) {
391
+ (_b = (_a = agent.panel).collapse) == null ? void 0 : _b.call(_a);
392
+ (_d = (_c = agent.panel).hide) == null ? void 0 : _d.call(_c);
393
+ }
394
+ const panelNode = document.getElementById("page-agent-runtime_agent-panel");
395
+ if (panelNode) {
396
+ panelNode.style.display = "none";
397
+ panelNode.style.opacity = "0";
398
+ }
399
+ }
400
+ resolveAgentInitErrorMessage(error) {
401
+ const raw = error instanceof Error ? error.message : String(error || "");
402
+ if (/Cannot read properties of undefined \(reading 'indexOf'\)/i.test(raw)) {
403
+ return "Page Agent \u8FD0\u884C\u65F6\u4F9D\u8D56\u52A0\u8F7D\u5931\u8D25\uFF08\u65E7\u7248\u6784\u5EFA\u517C\u5BB9\u95EE\u9898\uFF09\uFF0C\u8BF7\u5347\u7EA7 voice-page-agent \u5E76\u91CD\u88C5\u4F9D\u8D56\u3002";
404
+ }
405
+ return raw || "Page Agent \u521D\u59CB\u5316\u5931\u8D25";
406
+ }
343
407
  async executeVoiceCommand(rawCommand) {
344
408
  const command = this.sanitizeVoiceCommand(rawCommand);
345
409
  if (!command) {
@@ -478,102 +542,122 @@ var VOICE_PAGE_AGENT_KEY = "VOICE_PAGE_AGENT_INSTANCE";
478
542
  var VOICE_PAGE_AGENT_STYLE_ID = "voice-page-agent-style";
479
543
  var VOICE_PAGE_AGENT_STYLE_TEXT = `
480
544
  .voice-page-agent-root {
481
- --voice-page-agent-wake-bg: linear-gradient(135deg, #22c1ff, #3366ff);
545
+ --voice-page-agent-wake-bg: linear-gradient(135deg, #7f67ff, #5a8dff);
482
546
  --voice-page-agent-wake-color: #ffffff;
483
- --voice-page-agent-open-bg: linear-gradient(135deg, #ffa84a, #ff5f6d);
484
- --voice-page-agent-open-color: #ffffff;
485
- --voice-page-agent-status-color: #e2e8f0;
486
- --voice-page-agent-surface-bg: linear-gradient(135deg, rgba(15, 23, 42, 0.92), rgba(30, 41, 59, 0.9));
487
- --voice-page-agent-surface-border: rgba(148, 163, 184, 0.3);
547
+ --voice-page-agent-open-bg: linear-gradient(180deg, #ffffff, #f7f4ff);
548
+ --voice-page-agent-open-color: #30264d;
549
+ --voice-page-agent-status-color: #5f5a79;
488
550
 
489
- position: relative;
490
551
  display: flex;
491
552
  flex-direction: column;
553
+ align-items: flex-end;
492
554
  gap: 12px;
493
- margin-top: 12px;
494
- padding: 14px;
495
- border-radius: 16px;
496
- border: 1px solid var(--voice-page-agent-surface-border);
497
- background: var(--voice-page-agent-surface-bg);
498
- box-shadow:
499
- 0 16px 34px -26px rgba(15, 23, 42, 0.9),
500
- inset 0 1px 0 rgba(255, 255, 255, 0.12);
501
- overflow: hidden;
502
- }
503
-
504
- .voice-page-agent-root::before {
505
- content: "";
506
- position: absolute;
507
- inset: -35% -10% auto;
508
- height: 58%;
509
- background: radial-gradient(ellipse at center, rgba(56, 189, 248, 0.2), rgba(56, 189, 248, 0));
510
- pointer-events: none;
555
+ margin: 0;
556
+ padding: 0;
557
+ border: 0;
558
+ background: transparent;
559
+ box-shadow: none;
511
560
  }
512
561
 
513
562
  .voice-page-agent-actions {
514
- position: relative;
515
- z-index: 1;
516
563
  display: flex;
517
- flex-wrap: wrap;
564
+ align-items: center;
565
+ justify-content: flex-end;
566
+ flex-wrap: nowrap;
518
567
  gap: 10px;
519
568
  }
520
569
 
521
570
  .voice-page-agent-btn {
522
- border: 0;
571
+ border: 1px solid transparent;
523
572
  border-radius: 999px;
524
- padding: 9px 16px;
525
- font-size: 13px;
526
- line-height: 1.3;
573
+ padding: 10px 16px;
574
+ font-size: 16px;
575
+ line-height: 1.2;
527
576
  font-weight: 600;
528
- letter-spacing: 0.1px;
577
+ letter-spacing: 0;
529
578
  cursor: pointer;
530
- box-shadow:
531
- 0 10px 20px -14px rgba(15, 23, 42, 1),
532
- inset 0 1px 0 rgba(255, 255, 255, 0.22);
533
- transition: transform 0.2s ease, filter 0.2s ease, box-shadow 0.2s ease;
579
+ transition: transform 0.16s ease, box-shadow 0.16s ease, filter 0.16s ease;
580
+ white-space: nowrap;
581
+ user-select: none;
534
582
  }
535
583
 
536
584
  .voice-page-agent-btn--wake {
537
585
  background: var(--voice-page-agent-wake-bg);
538
586
  color: var(--voice-page-agent-wake-color);
587
+ border-color: rgba(129, 111, 214, 0.4);
588
+ box-shadow:
589
+ 0 8px 20px -14px rgba(95, 77, 170, 0.8),
590
+ inset 0 1px 0 rgba(255, 255, 255, 0.24);
539
591
  }
540
592
 
541
593
  .voice-page-agent-btn--open {
542
594
  background: var(--voice-page-agent-open-bg);
543
595
  color: var(--voice-page-agent-open-color);
596
+ border-color: rgba(169, 149, 255, 0.48);
597
+ box-shadow:
598
+ 0 8px 18px -14px rgba(102, 80, 188, 0.7),
599
+ 0 2px 8px rgba(155, 129, 247, 0.18);
600
+ display: inline-flex;
601
+ align-items: center;
602
+ gap: 10px;
603
+ min-height: 48px;
604
+ padding: 10px 20px;
544
605
  }
545
606
 
546
607
  .voice-page-agent-btn:hover {
547
608
  transform: translateY(-1px);
548
- filter: brightness(1.03);
549
- box-shadow:
550
- 0 14px 24px -14px rgba(15, 23, 42, 0.95),
551
- inset 0 1px 0 rgba(255, 255, 255, 0.24);
609
+ filter: brightness(1.01);
552
610
  }
553
611
 
554
612
  .voice-page-agent-btn:active {
555
613
  transform: translateY(0);
556
- filter: brightness(0.98);
614
+ filter: brightness(0.99);
615
+ }
616
+
617
+ .voice-page-agent-open-icon {
618
+ width: 20px;
619
+ height: 20px;
620
+ border-radius: 6px;
621
+ border: 2px solid #9d84ff;
622
+ color: #9d84ff;
623
+ display: inline-flex;
624
+ align-items: center;
625
+ justify-content: center;
626
+ font-size: 11px;
627
+ line-height: 1;
628
+ box-sizing: border-box;
629
+ }
630
+
631
+ .voice-page-agent-open-icon::before {
632
+ content: "\u2726";
633
+ }
634
+
635
+ .voice-page-agent-open-label {
636
+ line-height: 1;
557
637
  }
558
638
 
559
639
  .voice-page-agent-status {
560
640
  margin: 0;
561
- position: relative;
562
- z-index: 1;
641
+ max-width: min(420px, calc(100vw - 24px));
642
+ padding: 10px 16px;
643
+ border-radius: 999px;
644
+ border: 1px solid rgba(180, 166, 255, 0.56);
645
+ background: rgba(250, 248, 255, 0.9);
563
646
  color: var(--voice-page-agent-status-color);
564
- font-size: 13px;
647
+ font-size: 15px;
565
648
  line-height: 1.4;
566
- opacity: 0.95;
649
+ box-shadow: 0 8px 20px -18px rgba(98, 78, 170, 0.7);
650
+ backdrop-filter: blur(6px);
567
651
  }
568
652
  `;
569
653
  var DEFAULT_BUTTON_CONFIG = {
570
654
  startText: "\u5F00\u542F\u8BED\u97F3\u5524\u9192",
571
655
  wakeOnText: "\u8BED\u97F3\u5524\u9192\u4E2D",
572
656
  openText: "\u7F51\u9875\u52A9\u624B",
573
- wakeButtonBackground: "linear-gradient(135deg, #22c1ff, #3366ff)",
657
+ wakeButtonBackground: "linear-gradient(135deg, #7f67ff, #5a8dff)",
574
658
  wakeButtonTextColor: "#ffffff",
575
- openButtonBackground: "linear-gradient(135deg, #ffa84a, #ff5f6d)",
576
- openButtonTextColor: "#ffffff"
659
+ openButtonBackground: "linear-gradient(180deg, #ffffff, #f7f4ff)",
660
+ openButtonTextColor: "#30264d"
577
661
  };
578
662
  var globalButtonConfig = {
579
663
  ...DEFAULT_BUTTON_CONFIG
@@ -634,6 +718,16 @@ function useVoicePageAgent() {
634
718
  if (defaultController) return defaultController;
635
719
  throw new Error("voice-page-agent: controller not found, please install plugin first.");
636
720
  }
721
+ function resolveClickProps(handler) {
722
+ return {
723
+ // Vue3
724
+ onClick: handler,
725
+ // Vue2 render function listeners
726
+ on: {
727
+ click: handler
728
+ }
729
+ };
730
+ }
637
731
  var VoicePageAgentButton = defineComponent({
638
732
  name: "VoicePageAgentButton",
639
733
  props: {
@@ -692,7 +786,7 @@ var VoicePageAgentButton = defineComponent({
692
786
  }
693
787
  };
694
788
  const handleOpenClick = () => {
695
- void controller.openAgent();
789
+ void controller.toggleAgentPanel();
696
790
  };
697
791
  return () => {
698
792
  var _a, _b, _c, _d, _e, _f, _g;
@@ -716,7 +810,7 @@ var VoicePageAgentButton = defineComponent({
716
810
  {
717
811
  type: "button",
718
812
  class: "voice-page-agent-btn voice-page-agent-btn--wake",
719
- onClick: handleWakeClick
813
+ ...resolveClickProps(handleWakeClick)
720
814
  },
721
815
  state.value.enabled ? resolvedWakeOnText : resolvedStartText
722
816
  ) : null,
@@ -725,9 +819,12 @@ var VoicePageAgentButton = defineComponent({
725
819
  {
726
820
  type: "button",
727
821
  class: "voice-page-agent-btn voice-page-agent-btn--open",
728
- onClick: handleOpenClick
822
+ ...resolveClickProps(handleOpenClick)
729
823
  },
730
- resolvedOpenText
824
+ [
825
+ h("span", { class: "voice-page-agent-open-icon", "aria-hidden": "true" }),
826
+ h("span", { class: "voice-page-agent-open-label" }, resolvedOpenText)
827
+ ]
731
828
  )
732
829
  ]),
733
830
  props.showStatus ? h("p", { class: "voice-page-agent-status" }, state.value.message) : null