@nextpa/chat-core 0.1.0

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.
Files changed (149) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/dist/constants/defaults.d.ts +6 -0
  4. package/dist/constants/defaults.js +69 -0
  5. package/dist/core/chat-manager.d.ts +17 -0
  6. package/dist/core/chat-manager.js +39 -0
  7. package/dist/core/config-manager.d.ts +14 -0
  8. package/dist/core/config-manager.js +75 -0
  9. package/dist/core/connection-manager.d.ts +68 -0
  10. package/dist/core/connection-manager.js +273 -0
  11. package/dist/core/connection-retry-handler.d.ts +11 -0
  12. package/dist/core/connection-retry-handler.js +33 -0
  13. package/dist/core/consent-manager.d.ts +15 -0
  14. package/dist/core/consent-manager.js +40 -0
  15. package/dist/core/conversation-persistence.d.ts +23 -0
  16. package/dist/core/conversation-persistence.js +109 -0
  17. package/dist/core/event-emitter.d.ts +7 -0
  18. package/dist/core/event-emitter.js +27 -0
  19. package/dist/core/greeting-gate.d.ts +16 -0
  20. package/dist/core/greeting-gate.js +53 -0
  21. package/dist/core/index.d.ts +9 -0
  22. package/dist/core/index.js +7 -0
  23. package/dist/core/link-target.d.ts +15 -0
  24. package/dist/core/link-target.js +64 -0
  25. package/dist/core/local-storage-persistence.d.ts +11 -0
  26. package/dist/core/local-storage-persistence.js +111 -0
  27. package/dist/core/navigation-manager.d.ts +24 -0
  28. package/dist/core/navigation-manager.js +132 -0
  29. package/dist/core/popover-manager.d.ts +14 -0
  30. package/dist/core/popover-manager.js +36 -0
  31. package/dist/core/session-beacon.d.ts +11 -0
  32. package/dist/core/session-beacon.js +60 -0
  33. package/dist/core/text-connection-manager.d.ts +58 -0
  34. package/dist/core/text-connection-manager.js +200 -0
  35. package/dist/core/text-mode-manager.d.ts +50 -0
  36. package/dist/core/text-mode-manager.js +154 -0
  37. package/dist/core/text-types.d.ts +20 -0
  38. package/dist/core/text-types.js +1 -0
  39. package/dist/core/text-widget-controller.d.ts +47 -0
  40. package/dist/core/text-widget-controller.js +278 -0
  41. package/dist/core/theme-manager.d.ts +10 -0
  42. package/dist/core/theme-manager.js +25 -0
  43. package/dist/core/types.d.ts +50 -0
  44. package/dist/core/types.js +1 -0
  45. package/dist/core/voice-state-manager.d.ts +85 -0
  46. package/dist/core/voice-state-manager.js +317 -0
  47. package/dist/core/widget-controller.d.ts +58 -0
  48. package/dist/core/widget-controller.js +533 -0
  49. package/dist/core/widget-core.d.ts +51 -0
  50. package/dist/core/widget-core.js +160 -0
  51. package/dist/google.d.ts +1 -0
  52. package/dist/google.js +12 -0
  53. package/dist/index.d.ts +37 -0
  54. package/dist/index.js +40 -0
  55. package/dist/openai.d.ts +1 -0
  56. package/dist/openai.js +7 -0
  57. package/dist/services/api.d.ts +114 -0
  58. package/dist/services/api.js +336 -0
  59. package/dist/services/index.d.ts +3 -0
  60. package/dist/services/index.js +3 -0
  61. package/dist/services/page-interaction/constants.d.ts +1 -0
  62. package/dist/services/page-interaction/constants.js +1 -0
  63. package/dist/services/page-interaction/content-extractor.d.ts +2 -0
  64. package/dist/services/page-interaction/content-extractor.js +104 -0
  65. package/dist/services/page-interaction/deep-query.d.ts +8 -0
  66. package/dist/services/page-interaction/deep-query.js +44 -0
  67. package/dist/services/page-interaction/dom-executor.d.ts +7 -0
  68. package/dist/services/page-interaction/dom-executor.js +172 -0
  69. package/dist/services/page-interaction/dom-extractor.d.ts +8 -0
  70. package/dist/services/page-interaction/dom-extractor.js +252 -0
  71. package/dist/services/page-interaction/extension-bridge.d.ts +10 -0
  72. package/dist/services/page-interaction/extension-bridge.js +86 -0
  73. package/dist/services/page-interaction/iframe-navigation-manager.d.ts +28 -0
  74. package/dist/services/page-interaction/iframe-navigation-manager.js +154 -0
  75. package/dist/services/page-interaction/index.d.ts +5 -0
  76. package/dist/services/page-interaction/index.js +4 -0
  77. package/dist/services/page-interaction/page-interaction-handler.d.ts +21 -0
  78. package/dist/services/page-interaction/page-interaction-handler.js +129 -0
  79. package/dist/services/page-interaction/selector-generator.d.ts +1 -0
  80. package/dist/services/page-interaction/selector-generator.js +48 -0
  81. package/dist/services/page-interaction/types.d.ts +75 -0
  82. package/dist/services/page-interaction/types.js +1 -0
  83. package/dist/services/realtime/google/google-audio.d.ts +44 -0
  84. package/dist/services/realtime/google/google-audio.js +410 -0
  85. package/dist/services/realtime/google/google-provider.d.ts +47 -0
  86. package/dist/services/realtime/google/google-provider.js +465 -0
  87. package/dist/services/realtime/google/google-tool-mapper.d.ts +3 -0
  88. package/dist/services/realtime/google/google-tool-mapper.js +70 -0
  89. package/dist/services/realtime/google/index.d.ts +1 -0
  90. package/dist/services/realtime/google/index.js +1 -0
  91. package/dist/services/realtime/openai/index.d.ts +1 -0
  92. package/dist/services/realtime/openai/index.js +1 -0
  93. package/dist/services/realtime/openai/openai-audio-monitor.d.ts +1 -0
  94. package/dist/services/realtime/openai/openai-audio-monitor.js +55 -0
  95. package/dist/services/realtime/openai/openai-provider.d.ts +50 -0
  96. package/dist/services/realtime/openai/openai-provider.js +579 -0
  97. package/dist/services/realtime/openai/openai-tool-mapper.d.ts +15 -0
  98. package/dist/services/realtime/openai/openai-tool-mapper.js +14 -0
  99. package/dist/services/realtime/provider-factory.d.ts +4 -0
  100. package/dist/services/realtime/provider-factory.js +12 -0
  101. package/dist/services/realtime/types.d.ts +78 -0
  102. package/dist/services/realtime/types.js +1 -0
  103. package/dist/services/realtime/vertexai/index.d.ts +1 -0
  104. package/dist/services/realtime/vertexai/index.js +1 -0
  105. package/dist/services/realtime/vertexai/vertexai-provider.d.ts +53 -0
  106. package/dist/services/realtime/vertexai/vertexai-provider.js +561 -0
  107. package/dist/services/realtime/voice-session-tracker.d.ts +10 -0
  108. package/dist/services/realtime/voice-session-tracker.js +62 -0
  109. package/dist/services/signalr.d.ts +37 -0
  110. package/dist/services/signalr.js +145 -0
  111. package/dist/services/thinking-audio-pulse.d.ts +2 -0
  112. package/dist/services/thinking-audio-pulse.js +72 -0
  113. package/dist/services/thinking-audio.d.ts +2 -0
  114. package/dist/services/thinking-audio.js +105 -0
  115. package/dist/services/voice-health-watchdog.d.ts +42 -0
  116. package/dist/services/voice-health-watchdog.js +90 -0
  117. package/dist/services/webrtc-event-handler.d.ts +4 -0
  118. package/dist/services/webrtc-event-handler.js +42 -0
  119. package/dist/services/webrtc-greeting.d.ts +3 -0
  120. package/dist/services/webrtc-greeting.js +62 -0
  121. package/dist/services/webrtc-microphone.d.ts +15 -0
  122. package/dist/services/webrtc-microphone.js +64 -0
  123. package/dist/services/webrtc.d.ts +44 -0
  124. package/dist/services/webrtc.js +196 -0
  125. package/dist/types/index.d.ts +151 -0
  126. package/dist/types/index.js +1 -0
  127. package/dist/utils/audio-context.d.ts +11 -0
  128. package/dist/utils/audio-context.js +33 -0
  129. package/dist/utils/connect-chime.d.ts +11 -0
  130. package/dist/utils/connect-chime.js +230 -0
  131. package/dist/utils/consent.d.ts +4 -0
  132. package/dist/utils/consent.js +30 -0
  133. package/dist/utils/language-detection.d.ts +1 -0
  134. package/dist/utils/language-detection.js +17 -0
  135. package/dist/utils/logger.d.ts +13 -0
  136. package/dist/utils/logger.js +40 -0
  137. package/dist/utils/mic-level-analyser.d.ts +13 -0
  138. package/dist/utils/mic-level-analyser.js +50 -0
  139. package/dist/utils/proactive-events.d.ts +5 -0
  140. package/dist/utils/proactive-events.js +1 -0
  141. package/dist/utils/styles.d.ts +4 -0
  142. package/dist/utils/styles.js +35 -0
  143. package/dist/utils/theme-detection.d.ts +3 -0
  144. package/dist/utils/theme-detection.js +121 -0
  145. package/dist/utils/tool-status.d.ts +10 -0
  146. package/dist/utils/tool-status.js +61 -0
  147. package/dist/utils/ui-sounds.d.ts +3 -0
  148. package/dist/utils/ui-sounds.js +57 -0
  149. package/package.json +56 -0
@@ -0,0 +1,154 @@
1
+ import { logger } from '../../utils/logger';
2
+ import { NEXTPA_IFRAME_NAME } from './constants';
3
+ const IFRAME_Z_INDEX = '2147483640';
4
+ const WIDGET_Z_INDEX = '2147483641';
5
+ const BLOCK_DETECTION_TIMEOUT_MS = 3000;
6
+ export class IframeNavigationManager {
7
+ overlay = null;
8
+ iframe = null;
9
+ closeCallbacks = [];
10
+ widgetElevated = false;
11
+ previousOverflow = '';
12
+ navigateTo(url) {
13
+ const existingIframe = this.iframe
14
+ ?? document.querySelector(`iframe[name="${NEXTPA_IFRAME_NAME}"]`);
15
+ if (existingIframe) {
16
+ this.iframe = existingIframe;
17
+ this.overlay = existingIframe.parentElement;
18
+ return this.navigateExistingIframe(url);
19
+ }
20
+ return this.createIframeOverlay(url);
21
+ }
22
+ close() {
23
+ if (!this.overlay)
24
+ return;
25
+ this.cleanup();
26
+ for (const cb of this.closeCallbacks) {
27
+ try {
28
+ cb();
29
+ }
30
+ catch { /* swallow */ }
31
+ }
32
+ }
33
+ isActive() {
34
+ return this.iframe !== null && this.overlay !== null;
35
+ }
36
+ getTargetDocument() {
37
+ if (!this.iframe)
38
+ return document;
39
+ try {
40
+ return this.iframe.contentDocument ?? document;
41
+ }
42
+ catch {
43
+ return document;
44
+ }
45
+ }
46
+ getTargetWindow() {
47
+ if (!this.iframe)
48
+ return globalThis;
49
+ try {
50
+ const win = this.iframe.contentWindow;
51
+ if (win?.location.href) {
52
+ return win;
53
+ }
54
+ }
55
+ catch {
56
+ return globalThis;
57
+ }
58
+ return globalThis;
59
+ }
60
+ onClose(callback) {
61
+ this.closeCallbacks.push(callback);
62
+ }
63
+ createIframeOverlay(url) {
64
+ this.close();
65
+ this.elevateWidget();
66
+ this.hideParentScrollbar();
67
+ return new Promise((resolve) => {
68
+ const overlay = document.createElement('div');
69
+ overlay.dataset.nextpaIframeNav = 'true';
70
+ overlay.style.cssText = [
71
+ 'position: fixed',
72
+ 'inset: 0',
73
+ `z-index: ${IFRAME_Z_INDEX}`,
74
+ 'background: #fff',
75
+ ].join('; ');
76
+ const iframe = document.createElement('iframe');
77
+ iframe.style.cssText = 'border: none; width: 100%; height: 100%';
78
+ iframe.name = NEXTPA_IFRAME_NAME;
79
+ iframe.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox');
80
+ overlay.appendChild(iframe);
81
+ document.body.appendChild(overlay);
82
+ this.overlay = overlay;
83
+ this.iframe = iframe;
84
+ this.loadUrlInIframe(iframe, url, resolve);
85
+ });
86
+ }
87
+ navigateExistingIframe(url) {
88
+ return new Promise((resolve) => {
89
+ this.loadUrlInIframe(this.iframe, url, resolve);
90
+ });
91
+ }
92
+ loadUrlInIframe(iframe, url, resolve) {
93
+ let resolved = false;
94
+ const settle = (result) => {
95
+ if (resolved)
96
+ return;
97
+ resolved = true;
98
+ clearTimeout(timeoutId);
99
+ iframe.removeEventListener('load', onLoad);
100
+ iframe.removeEventListener('error', onError);
101
+ if (result.status === 'blocked') {
102
+ this.cleanup();
103
+ }
104
+ resolve(result);
105
+ };
106
+ const timeoutId = setTimeout(() => {
107
+ settle({ status: 'blocked', reason: 'Timeout: page did not load within detection window.' });
108
+ }, BLOCK_DETECTION_TIMEOUT_MS);
109
+ const onLoad = () => {
110
+ try {
111
+ const iframeDoc = iframe.contentDocument;
112
+ if (!iframeDoc) {
113
+ throw new Error('contentDocument is null');
114
+ }
115
+ // Access title to trigger cross-origin exception if blocked
116
+ logger.debug('[IframeNav] Loaded in iframe:', url, 'title:', iframeDoc.title);
117
+ settle({ status: 'iframe-loaded' });
118
+ }
119
+ catch {
120
+ logger.debug('[IframeNav] Blocked by cross-origin policy:', url);
121
+ settle({ status: 'blocked', reason: 'Cross-origin restrictions prevent iframe access.' });
122
+ }
123
+ };
124
+ const onError = () => {
125
+ settle({ status: 'blocked', reason: 'Failed to load URL in iframe.' });
126
+ };
127
+ iframe.addEventListener('load', onLoad);
128
+ iframe.addEventListener('error', onError);
129
+ iframe.src = url;
130
+ }
131
+ elevateWidget() {
132
+ if (this.widgetElevated)
133
+ return;
134
+ const widget = document.querySelector('nextpa-widget');
135
+ if (!widget)
136
+ return;
137
+ widget.style.position = 'relative';
138
+ widget.style.zIndex = WIDGET_Z_INDEX;
139
+ this.widgetElevated = true;
140
+ }
141
+ hideParentScrollbar() {
142
+ this.previousOverflow = document.documentElement.style.overflow;
143
+ document.documentElement.style.overflow = 'hidden';
144
+ }
145
+ restoreParentScrollbar() {
146
+ document.documentElement.style.overflow = this.previousOverflow;
147
+ }
148
+ cleanup() {
149
+ this.restoreParentScrollbar();
150
+ this.overlay?.remove();
151
+ this.overlay = null;
152
+ this.iframe = null;
153
+ }
154
+ }
@@ -0,0 +1,5 @@
1
+ export { extractPageSnapshot, extractForms, extractButtons, extractLinks, extractTables, extractProductCards, extractInteractiveElements } from './dom-extractor';
2
+ export { extractPageContent } from './content-extractor';
3
+ export { fillField, fillFields, clickElement, scrollToElement, highlightElement, waitForElement } from './dom-executor';
4
+ export { generateSelector } from './selector-generator';
5
+ export type { PageSnapshot, FormElement, ButtonElement, LinkElement, TableElement, ProductCardElement, InteractiveElement, PageContent, PageInteractionRequest, PageInteractionResult, ActionResult } from './types';
@@ -0,0 +1,4 @@
1
+ export { extractPageSnapshot, extractForms, extractButtons, extractLinks, extractTables, extractProductCards, extractInteractiveElements } from './dom-extractor';
2
+ export { extractPageContent } from './content-extractor';
3
+ export { fillField, fillFields, clickElement, scrollToElement, highlightElement, waitForElement } from './dom-executor';
4
+ export { generateSelector } from './selector-generator';
@@ -0,0 +1,21 @@
1
+ import type * as signalR from '@microsoft/signalr';
2
+ import type { PageInteractionRequest, PageInteractionResult } from './types';
3
+ export type DocumentProvider = () => Document;
4
+ export type WindowProvider = () => Window;
5
+ export type ExternalExecutor = (request: PageInteractionRequest) => Promise<PageInteractionResult | string>;
6
+ export declare class PageInteractionHandler {
7
+ private readonly getConnection;
8
+ private requestTimestamps;
9
+ private getDocument;
10
+ private getWindow;
11
+ private externalExecutor;
12
+ constructor(getConnection: () => signalR.HubConnection | null);
13
+ setDocumentProvider(getDoc: DocumentProvider, getWin: WindowProvider): void;
14
+ setExternalExecutor(executor: ExternalExecutor | null): void;
15
+ handleRequest(requestJson: string): Promise<void>;
16
+ private executeAction;
17
+ private toResult;
18
+ private sendResponse;
19
+ private validateRequest;
20
+ private checkRateLimit;
21
+ }
@@ -0,0 +1,129 @@
1
+ import { logger } from '../../utils/logger';
2
+ import { extractPageSnapshot } from './dom-extractor';
3
+ import { extractPageContent } from './content-extractor';
4
+ import { clickElement, fillField, fillFields, highlightElement, scrollToElement, waitForElement } from './dom-executor';
5
+ const ALLOWED_ACTIONS = new Set(['read', 'read_content', 'fill', 'fill_multiple', 'click', 'scroll_to', 'highlight', 'wait_for']);
6
+ const MAX_REQUESTS_PER_SECOND = 10;
7
+ const DANGEROUS_SELECTOR_PATTERN = /javascript:|<script|on\w+\s*=/i;
8
+ export class PageInteractionHandler {
9
+ getConnection;
10
+ requestTimestamps = [];
11
+ getDocument = () => document;
12
+ getWindow = () => globalThis;
13
+ externalExecutor = null;
14
+ constructor(getConnection) {
15
+ this.getConnection = getConnection;
16
+ }
17
+ setDocumentProvider(getDoc, getWin) {
18
+ this.getDocument = getDoc;
19
+ this.getWindow = getWin;
20
+ }
21
+ setExternalExecutor(executor) {
22
+ this.externalExecutor = executor;
23
+ }
24
+ async handleRequest(requestJson) {
25
+ let request;
26
+ try {
27
+ request = JSON.parse(requestJson);
28
+ }
29
+ catch {
30
+ logger.error('[PageInteraction] Failed to parse request JSON');
31
+ return;
32
+ }
33
+ if (!this.validateRequest(request))
34
+ return;
35
+ if (!this.checkRateLimit()) {
36
+ await this.sendResponse(request.requestId, {
37
+ success: false,
38
+ errorMessage: 'Rate limit exceeded. Too many requests.',
39
+ });
40
+ return;
41
+ }
42
+ const result = this.externalExecutor
43
+ ? await this.externalExecutor(request)
44
+ : await this.executeAction(request);
45
+ await this.sendResponse(request.requestId, result);
46
+ }
47
+ async executeAction(request) {
48
+ const doc = this.getDocument();
49
+ const win = this.getWindow();
50
+ switch (request.action) {
51
+ case 'read': {
52
+ const snapshot = extractPageSnapshot(doc, win);
53
+ return JSON.stringify(snapshot);
54
+ }
55
+ case 'read_content': {
56
+ const content = extractPageContent(doc, win);
57
+ return JSON.stringify(content);
58
+ }
59
+ case 'fill':
60
+ return this.toResult(fillField(request.selector, request.value, doc));
61
+ case 'fill_multiple':
62
+ return this.toResult(fillFields(request.fields, doc));
63
+ case 'click':
64
+ return this.toResult(clickElement(request.selector, doc));
65
+ case 'scroll_to':
66
+ return this.toResult(scrollToElement(request.selector, doc));
67
+ case 'highlight':
68
+ return this.toResult(highlightElement(request.selector, undefined, undefined, doc));
69
+ case 'wait_for':
70
+ return this.toResult(await waitForElement(request.selector, request.value ? Number(request.value) : undefined, doc));
71
+ default:
72
+ return { success: false, errorMessage: `Unknown action: ${request.action}` };
73
+ }
74
+ }
75
+ toResult(actionResult) {
76
+ return {
77
+ success: actionResult.success,
78
+ errorMessage: actionResult.errorMessage,
79
+ };
80
+ }
81
+ async sendResponse(requestId, result) {
82
+ const connection = this.getConnection();
83
+ if (!connection) {
84
+ logger.error('[PageInteraction] No SignalR connection available to send response');
85
+ return;
86
+ }
87
+ try {
88
+ const responseJson = typeof result === 'string' ? result : JSON.stringify(result);
89
+ await connection.invoke('SendPageInteractionResponse', requestId, responseJson);
90
+ logger.debug('[PageInteraction] Response sent for request:', requestId);
91
+ }
92
+ catch (error) {
93
+ logger.error('[PageInteraction] Failed to send response:', error);
94
+ }
95
+ }
96
+ validateRequest(request) {
97
+ if (!request.requestId || !request.action) {
98
+ logger.warn('[PageInteraction] Invalid request: missing requestId or action');
99
+ return false;
100
+ }
101
+ if (!ALLOWED_ACTIONS.has(request.action)) {
102
+ logger.warn('[PageInteraction] Unknown action:', request.action);
103
+ return false;
104
+ }
105
+ if (request.selector && DANGEROUS_SELECTOR_PATTERN.test(request.selector)) {
106
+ logger.warn('[PageInteraction] Dangerous selector rejected:', request.selector);
107
+ return false;
108
+ }
109
+ if (request.fields) {
110
+ for (const selector of Object.keys(request.fields)) {
111
+ if (DANGEROUS_SELECTOR_PATTERN.test(selector)) {
112
+ logger.warn('[PageInteraction] Dangerous selector in fields rejected:', selector);
113
+ return false;
114
+ }
115
+ }
116
+ }
117
+ return true;
118
+ }
119
+ checkRateLimit() {
120
+ const now = Date.now();
121
+ this.requestTimestamps = this.requestTimestamps.filter(t => now - t < 1000);
122
+ if (this.requestTimestamps.length >= MAX_REQUESTS_PER_SECOND) {
123
+ logger.warn('[PageInteraction] Rate limit exceeded');
124
+ return false;
125
+ }
126
+ this.requestTimestamps.push(now);
127
+ return true;
128
+ }
129
+ }
@@ -0,0 +1 @@
1
+ export declare function generateSelector(element: Element, doc?: Document): string;
@@ -0,0 +1,48 @@
1
+ export function generateSelector(element, doc = document) {
2
+ const dataTestId = element.dataset?.testid;
3
+ if (dataTestId) {
4
+ const selector = `[data-testid="${CSS.escape(dataTestId)}"]`;
5
+ if (doc.querySelectorAll(selector).length === 1) {
6
+ return selector;
7
+ }
8
+ }
9
+ if (element.id) {
10
+ return `#${CSS.escape(element.id)}`;
11
+ }
12
+ const name = element.getAttribute('name');
13
+ if (name) {
14
+ const tag = element.tagName.toLowerCase();
15
+ const selector = `${tag}[name="${CSS.escape(name)}"]`;
16
+ if (doc.querySelectorAll(selector).length === 1) {
17
+ return selector;
18
+ }
19
+ }
20
+ return buildNthChildPath(element, doc);
21
+ }
22
+ function buildNthChildPath(element, doc) {
23
+ const parts = [];
24
+ let current = element;
25
+ while (current !== null && current !== doc.documentElement) {
26
+ if (current.id) {
27
+ parts.unshift(`#${CSS.escape(current.id)}`);
28
+ break;
29
+ }
30
+ const parentEl = current.parentElement;
31
+ if (!parentEl) {
32
+ parts.unshift(current.tagName.toLowerCase());
33
+ break;
34
+ }
35
+ const currentTag = current.tagName;
36
+ const siblings = Array.from(parentEl.children);
37
+ const sameTagSiblings = siblings.filter((s) => s.tagName === currentTag);
38
+ if (sameTagSiblings.length === 1) {
39
+ parts.unshift(current.tagName.toLowerCase());
40
+ }
41
+ else {
42
+ const index = sameTagSiblings.indexOf(current) + 1;
43
+ parts.unshift(`${current.tagName.toLowerCase()}:nth-of-type(${index})`);
44
+ }
45
+ current = parentEl;
46
+ }
47
+ return parts.join(' > ');
48
+ }
@@ -0,0 +1,75 @@
1
+ export interface PageSnapshot {
2
+ url: string;
3
+ title: string | null;
4
+ forms: FormElement[];
5
+ buttons: ButtonElement[];
6
+ links: LinkElement[];
7
+ tables: TableElement[];
8
+ productCards: ProductCardElement[];
9
+ otherInteractiveElements: InteractiveElement[];
10
+ }
11
+ export interface FormElement {
12
+ selector: string;
13
+ formSelector: string | null;
14
+ label: string | null;
15
+ context: string | null;
16
+ inputType: string;
17
+ currentValue: string | null;
18
+ isRequired: boolean;
19
+ isDisabled: boolean;
20
+ options: string[] | null;
21
+ placeholder: string | null;
22
+ }
23
+ export interface ButtonElement {
24
+ selector: string;
25
+ text: string | null;
26
+ isDisabled: boolean;
27
+ type: string | null;
28
+ }
29
+ export interface LinkElement {
30
+ selector: string;
31
+ text: string | null;
32
+ href: string | null;
33
+ }
34
+ export interface TableElement {
35
+ selector: string;
36
+ headers: string[];
37
+ rowCount: number;
38
+ sampleRows: string[][] | null;
39
+ }
40
+ export interface ProductCardElement {
41
+ selector: string;
42
+ title: string | null;
43
+ price: string | null;
44
+ imageUrl: string | null;
45
+ description: string | null;
46
+ }
47
+ export interface InteractiveElement {
48
+ selector: string;
49
+ tagName: string;
50
+ text: string | null;
51
+ role: string | null;
52
+ ariaLabel: string | null;
53
+ }
54
+ export interface PageContent {
55
+ url: string;
56
+ title: string | null;
57
+ content: string;
58
+ truncated: boolean;
59
+ }
60
+ export interface PageInteractionRequest {
61
+ requestId: string;
62
+ action: string;
63
+ selector?: string;
64
+ value?: string;
65
+ fields?: Record<string, string>;
66
+ }
67
+ export interface PageInteractionResult {
68
+ success: boolean;
69
+ errorMessage?: string;
70
+ data?: string;
71
+ }
72
+ export interface ActionResult {
73
+ success: boolean;
74
+ errorMessage?: string;
75
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
1
+ export declare function resolveWorkletUrl(): string;
2
+ export declare class GoogleAudioHandler {
3
+ private captureContext;
4
+ private mediaStream;
5
+ private workletNode;
6
+ private playbackContext;
7
+ private gainNode;
8
+ private aecStreamDestination;
9
+ private loopbackSource;
10
+ private loopbackSink;
11
+ private playbackElement;
12
+ private scheduledTime;
13
+ private audioQueue;
14
+ private isMuted;
15
+ private isPlaying;
16
+ private capturePaused;
17
+ private speechDetected;
18
+ private silenceTimerId;
19
+ private speechStartTimerId;
20
+ private consecutiveSpeechFrames;
21
+ onAudioData: ((base64Pcm: string) => void) | null;
22
+ onSpeechStarted: (() => void) | null;
23
+ onSpeechEnded: (() => void) | null;
24
+ onAudioLevel: ((level01: number) => void) | null;
25
+ get isPlaybackActive(): boolean;
26
+ startCapture(): Promise<void>;
27
+ playAudio(base64Pcm: string): void;
28
+ private setupPlaybackChain;
29
+ private connectGainOutput;
30
+ private tryRouteThroughAecLoopback;
31
+ private teardownAecLoopback;
32
+ private enqueueAudio;
33
+ private schedulePlayback;
34
+ resume(): void;
35
+ pauseCapture(): void;
36
+ resumeCapture(): void;
37
+ setMuted(muted: boolean): void;
38
+ stop(): void;
39
+ private detectSpeech;
40
+ private handleSpeechFrame;
41
+ private handleSilenceFrame;
42
+ restartCapture(): Promise<void>;
43
+ clearPlaybackQueue(): void;
44
+ }