ttp-agent-sdk 2.1.11 β†’ 2.1.13

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.
@@ -1 +1 @@
1
- class AudioProcessor extends AudioWorkletProcessor{constructor(e){super(),this.config=e.processorOptions||{},this.sampleRate=this.config.sampleRate||16e3,this.bufferSize=128,this.buffer=new Float32Array(this.bufferSize),this.bufferIndex=0,this.silenceThreshold=.005,this.minVoiceDuration=100,this.pauseThreshold=3e3,this.isVoiceActive=!1,this.voiceStartTime=0,this.lastVoiceTime=0,this.consecutiveSilenceFrames=0,this.silenceFramesThreshold=5,this.frameCount=0,this.lastLogTime=0,this.continuousMode=!0,this.forceContinuous=!0,this.isCurrentlyStreaming=!1,this.sendBuffer=null,this.sendBufferBytes=0,console.log("🎀 AudioProcessor: Initialized with sample rate:",this.sampleRate),console.log("🎀 AudioProcessor: Buffer size:",this.bufferSize),console.log("🎀 AudioProcessor: Force continuous mode:",this.forceContinuous),this.port.onmessage=e=>{const{type:s,data:t}=e.data;switch(console.log("🎀 AudioProcessor: Received message:",s,t),s){case"start":this.isProcessing=!0,this.isCurrentlyStreaming=!0,console.log("🎀 AudioProcessor: Started processing");break;case"stop":this.isProcessing=!1,this.isCurrentlyStreaming=!1,this.isVoiceActive=!1,this.forceContinuous=!1,this.flushBuffer(),console.log("🎀 AudioProcessor: Stopped processing and flushed buffer");break;case"setForceContinuous":this.forceContinuous=t.enabled,this.isProcessing=!0,this.isCurrentlyStreaming=!0,console.log("🎀 AudioProcessor: Enabled continuous mode");break;case"flush":this.flushBuffer(),console.log("🎀 AudioProcessor: Flushing buffer");break;case"config":Object.assign(this.config,t),console.log("🎀 AudioProcessor: Updated config:",this.config)}}}process(e,s,t){const i=e[0],o=s[0];return i.length>0&&o.length>0&&o[0].set(i[0]),i.length>0&&i[0].length>0&&this.processAudioData(i[0]),!0}processAudioData(e){this.frameCount++;for(let s=0;s<e.length;s+=this.bufferSize){const t=Math.min(this.bufferSize,e.length-s);for(let i=0;i<t;i++)this.buffer[i]=e[s+i];for(let e=t;e<this.bufferSize;e++)this.buffer[e]=0;let i=0;for(let e=0;e<this.bufferSize;e++)i+=this.buffer[e]*this.buffer[e];const o=Math.sqrt(i/this.bufferSize);let r=0,n=0;for(let e=1;e<this.bufferSize;e++){const s=Math.abs(this.buffer[e]-this.buffer[e-1]);r+=s,s>.1&&n++}r/=this.bufferSize,this.bufferSize;const h=Date.now();let c=o>this.silenceThreshold;if(h-this.lastLogTime>2e3){const e=c?"VOICE":"SILENCE";console.log(`🎀 AudioProcessor: RMS: ${o.toFixed(4)}, Threshold: ${this.silenceThreshold}, Status: ${e}, Streaming: ${this.isCurrentlyStreaming}, ForceContinuous: ${this.forceContinuous}, VoiceActive: ${this.isVoiceActive}`),this.lastLogTime=h}const f=h-this.lastVoiceTime;this.forceContinuous||c?(this.consecutiveSilenceFrames=0,this.isVoiceActive||(this.isVoiceActive=!0,this.voiceStartTime=h,this.isCurrentlyStreaming=!0,console.log(`πŸ—£οΈ Voice detected (RMS: ${o.toFixed(4)})`)),this.lastVoiceTime=h):this.consecutiveSilenceFrames++,!this.forceContinuous&&!c&&this.isVoiceActive&&f>=200&&(this.isVoiceActive=!1,this.isCurrentlyStreaming=!1,console.log(`⏸️ AudioProcessor: Silence detected, stopping streaming (${f.toFixed(0)}ms silence)`),this.voiceStartTime=0,this.lastVoiceTime=0,this.consecutiveSilenceFrames=0),this.isCurrentlyStreaming&&this.isProcessing&&this.sendPCMAudioData(this.buffer)}}sendPCMAudioData(e){const s=new Int16Array(e.length);for(let t=0;t<e.length;t++){const i=Math.max(-1,Math.min(1,e[t]));s[t]=Math.round(32767*i)}for(this.sendBuffer||(this.sendBuffer=[],this.sendBufferBytes=0),this.sendBuffer.push(s),this.sendBufferBytes+=s.byteLength;this.sendBufferBytes>=4096;){let e=0,s=0;for(let t=0;t<this.sendBuffer.length;t++){const i=this.sendBuffer[t].byteLength;if(!(s+i<=4096))break;e++,s+=i}const t=this.sendBuffer.slice(0,e),i=t.reduce((e,s)=>e+s.length,0),o=new Int16Array(i);let r=0;for(const e of t)o.set(e,r),r+=e.length;Math.random()<.01&&console.log(`🎀 AudioProcessor: Sending PCM batch - ${o.byteLength} bytes (${e} chunks)`),this.port.postMessage({type:"pcm_audio_data",data:o,sampleRate:this.sampleRate,channelCount:1,frameCount:this.frameCount,batchSize:e,totalBytes:o.byteLength}),this.sendBuffer=this.sendBuffer.slice(e),this.sendBufferBytes-=s}}flushBuffer(){if(this.sendBuffer&&this.sendBuffer.length>0){const e=this.sendBuffer.reduce((e,s)=>e+s.length,0),s=new Int16Array(e);let t=0;for(const e of this.sendBuffer)s.set(e,t),t+=e.length;this.port.postMessage({type:"pcm_audio_data",data:s,sampleRate:this.sampleRate,channelCount:1,frameCount:this.frameCount,batchSize:this.sendBuffer.length,totalBytes:s.byteLength,isFlush:!0}),this.sendBuffer=[],this.sendBufferBytes=0}}}registerProcessor("audio-processor",AudioProcessor);
1
+ class AudioProcessor extends AudioWorkletProcessor{constructor(e){super(),this.config=e.processorOptions||{},this.sampleRate=this.config.sampleRate||16e3,this.bufferSize=128,this.buffer=new Float32Array(this.bufferSize),this.bufferIndex=0,this.silenceThreshold=.01,this.minVoiceDuration=100,this.pauseThreshold=3e3,this.isVoiceActive=!1,this.voiceStartTime=0,this.lastVoiceTime=0,this.consecutiveSilenceFrames=0,this.silenceFramesThreshold=5,this.frameCount=0,this.lastLogTime=0,this.continuousMode=!0,this.forceContinuous=!0,this.isCurrentlyStreaming=!1,this.sendBuffer=null,this.sendBufferBytes=0,this.port.onmessage=e=>{const{type:t,data:s}=e.data;switch(t){case"start":this.isProcessing=!0,this.isCurrentlyStreaming=!0;break;case"stop":this.isProcessing=!1,this.isCurrentlyStreaming=!1,this.isVoiceActive=!1,this.forceContinuous=!1,this.flushBuffer();break;case"setForceContinuous":this.forceContinuous=s.enabled,this.isProcessing=!0,this.isCurrentlyStreaming=!0;break;case"flush":this.flushBuffer();break;case"config":Object.assign(this.config,s)}}}process(e,t,s){const i=e[0],r=t[0];return i.length>0&&r.length>0&&r[0].set(i[0]),i.length>0&&i[0].length>0&&this.processAudioData(i[0]),!0}processAudioData(e){this.frameCount++;for(let t=0;t<e.length;t+=this.bufferSize){const s=Math.min(this.bufferSize,e.length-t);for(let i=0;i<s;i++)this.buffer[i]=e[t+i];for(let e=s;e<this.bufferSize;e++)this.buffer[e]=0;let i=0;for(let e=0;e<this.bufferSize;e++)i+=this.buffer[e]*this.buffer[e];const r=Math.sqrt(i/this.bufferSize);let h=0,n=0;for(let e=1;e<this.bufferSize;e++){const t=Math.abs(this.buffer[e]-this.buffer[e-1]);h+=t,t>.1&&n++}h/=this.bufferSize,this.bufferSize;const o=Date.now();let f=r>this.silenceThreshold;const a=o-this.lastVoiceTime;if(f)this.consecutiveSilenceFrames=0,this.isVoiceActive||(this.isVoiceActive=!0,this.voiceStartTime=o,this.isCurrentlyStreaming=!0),this.lastVoiceTime=o;else{this.consecutiveSilenceFrames++;const e=this.forceContinuous?1500:200;!f&&this.isVoiceActive&&a>=e&&(this.isVoiceActive=!1,this.isCurrentlyStreaming=!1,this.voiceStartTime=0,this.lastVoiceTime=0,this.consecutiveSilenceFrames=0)}this.isCurrentlyStreaming&&this.isProcessing&&this.sendPCMAudioData(this.buffer)}}sendPCMAudioData(e){const t=new Int16Array(e.length);for(let s=0;s<e.length;s++){const i=Math.max(-1,Math.min(1,e[s]));t[s]=Math.round(32767*i)}for(this.sendBuffer||(this.sendBuffer=[],this.sendBufferBytes=0),this.sendBuffer.push(t),this.sendBufferBytes+=t.byteLength;this.sendBufferBytes>=4096;){let e=0,t=0;for(let s=0;s<this.sendBuffer.length;s++){const i=this.sendBuffer[s].byteLength;if(!(t+i<=4096))break;e++,t+=i}const s=this.sendBuffer.slice(0,e),i=s.reduce((e,t)=>e+t.length,0),r=new Int16Array(i);let h=0;for(const e of s)r.set(e,h),h+=e.length;this.port.postMessage({type:"pcm_audio_data",data:r,sampleRate:this.sampleRate,channelCount:1,frameCount:this.frameCount,batchSize:e,totalBytes:r.byteLength}),this.sendBuffer=this.sendBuffer.slice(e),this.sendBufferBytes-=t}}flushBuffer(){if(this.sendBuffer&&this.sendBuffer.length>0){const e=this.sendBuffer.reduce((e,t)=>e+t.length,0),t=new Int16Array(e);let s=0;for(const e of this.sendBuffer)t.set(e,s),s+=e.length;this.port.postMessage({type:"pcm_audio_data",data:t,sampleRate:this.sampleRate,channelCount:1,frameCount:this.frameCount,batchSize:this.sendBuffer.length,totalBytes:t.byteLength,isFlush:!0}),this.sendBuffer=[],this.sendBufferBytes=0}}}registerProcessor("audio-processor",AudioProcessor);
@@ -84,6 +84,54 @@
84
84
  font-size: 12px;
85
85
  overflow-x: auto;
86
86
  margin: 20px 0;
87
+ white-space: pre;
88
+ }
89
+
90
+ .code-block pre {
91
+ margin: 0;
92
+ font-family: inherit;
93
+ }
94
+
95
+ .code-block code {
96
+ font-family: inherit;
97
+ white-space: pre;
98
+ }
99
+
100
+ .tabs {
101
+ display: flex;
102
+ gap: 10px;
103
+ margin-bottom: 15px;
104
+ border-bottom: 2px solid #E5E7EB;
105
+ }
106
+
107
+ .tab {
108
+ background: none;
109
+ border: none;
110
+ padding: 12px 24px;
111
+ cursor: pointer;
112
+ font-size: 14px;
113
+ font-weight: 600;
114
+ color: #6B7280;
115
+ border-bottom: 3px solid transparent;
116
+ transition: all 0.2s;
117
+ margin-bottom: -2px;
118
+ }
119
+
120
+ .tab:hover {
121
+ color: #4F46E5;
122
+ }
123
+
124
+ .tab.active {
125
+ color: #4F46E5;
126
+ border-bottom-color: #4F46E5;
127
+ }
128
+
129
+ .tab-content {
130
+ display: none;
131
+ }
132
+
133
+ .tab-content.active {
134
+ display: block;
87
135
  }
88
136
  </style>
89
137
  </head>
@@ -122,28 +170,157 @@
122
170
  </div>
123
171
 
124
172
  <h2>Implementation Code:</h2>
125
- <div class="code-block">
126
- const widget = new TTPAgentSDK.AgentWidget({
173
+ <div class="tabs">
174
+ <button class="tab active" onclick="switchTab('simple')">Simple</button>
175
+ <button class="tab" onclick="switchTab('advanced')">All Options</button>
176
+ </div>
177
+
178
+ <div id="simple-tab" class="tab-content active">
179
+ <div class="code-block"><pre><code>const widget = new TTPAgentSDK.AgentWidget({
127
180
  agentId: 'agent_87c4a55a1',
128
181
  appId: 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC',
129
182
 
130
- // Direct connection without signed link
131
- getSessionUrl: async ({ agentId, appId, variables }) => {
132
- // Direct WebSocket URL construction with demo flag
133
- const wsUrl = `wss://speech.talktopc.com/ws/conv?agentId=${agentId}&appId=${appId}&demo=true`;
134
- return wsUrl;
135
- },
183
+ primaryColor: '#10B981',
184
+ position: 'bottom-right'
185
+ });</code></pre></div>
186
+ </div>
187
+
188
+ <div id="advanced-tab" class="tab-content">
189
+ <div class="code-block"><pre><code>const widget = new TTPAgentSDK.AgentWidget({
190
+ // Required
191
+ agentId: 'agent_87c4a55a1',
192
+ appId: 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC',
193
+
194
+ // Optional: getSessionUrl - only needed for signed links or custom URL logic
195
+ // getSessionUrl: async ({ agentId, appId, variables }) => {
196
+ // const response = await fetch('https://your-backend.com/api/signed-url', {
197
+ // method: 'POST',
198
+ // headers: { 'Content-Type': 'application/json' },
199
+ // body: JSON.stringify({ agentId, appId, variables })
200
+ // });
201
+ // const data = await response.json();
202
+ // return data.signedUrl;
203
+ // },
204
+
205
+ // Simple styling (backward compatible)
206
+ primaryColor: '#10B981',
207
+ position: 'bottom-right', // or use advanced position object below
208
+
209
+ // Advanced Icon Configuration
210
+ // icon: {
211
+ // type: 'microphone', // 'microphone', 'custom', 'emoji', 'text'
212
+ // customImage: 'https://example.com/icon.png', // For type: 'custom'
213
+ // emoji: '🎀', // For type: 'emoji'
214
+ // text: 'AI', // For type: 'text'
215
+ // size: 'medium' // 'small', 'medium', 'large', 'xl'
216
+ // },
217
+
218
+ // Advanced Positioning
219
+ // position: {
220
+ // vertical: 'bottom', // 'top', 'bottom', 'center'
221
+ // horizontal: 'right', // 'left', 'right', 'center'
222
+ // offset: { x: 20, y: 20 } // Custom offset in pixels
223
+ // },
224
+
225
+ // Button Configuration
226
+ // button: {
227
+ // size: 'medium', // 'small', 'medium', 'large', 'xl'
228
+ // shape: 'circle', // 'circle', 'square', 'rounded'
229
+ // primaryColor: '#10B981',
230
+ // hoverColor: '#059669',
231
+ // activeColor: '#EF4444',
232
+ // shadow: true,
233
+ // shadowColor: 'rgba(0,0,0,0.15)'
234
+ // },
235
+
236
+ // Panel Configuration
237
+ // panel: {
238
+ // width: 350,
239
+ // height: 500,
240
+ // borderRadius: 12,
241
+ // backgroundColor: 'rgba(255,255,255,0.95)',
242
+ // backdropFilter: 'blur(10px)', // Glass morphism effect
243
+ // border: '1px solid rgba(0,0,0,0.1)'
244
+ // },
245
+
246
+ // Header Configuration
247
+ // header: {
248
+ // title: 'Voice Assistant',
249
+ // showTitle: true,
250
+ // backgroundColor: null, // Uses button primaryColor if null
251
+ // textColor: '#FFFFFF',
252
+ // showCloseButton: true
253
+ // },
254
+
255
+ // Messages Configuration
256
+ // messages: {
257
+ // userBackgroundColor: '#E5E7EB',
258
+ // agentBackgroundColor: '#F3F4F6',
259
+ // systemBackgroundColor: '#DCFCE7',
260
+ // errorBackgroundColor: '#FEE2E2',
261
+ // textColor: '#1F2937',
262
+ // fontSize: '14px',
263
+ // borderRadius: 8
264
+ // },
265
+
266
+ // Animation Configuration
267
+ // animation: {
268
+ // enableHover: true,
269
+ // enablePulse: true,
270
+ // enableSlide: true,
271
+ // duration: 0.3
272
+ // },
273
+
274
+ // Behavior Configuration
275
+ // behavior: {
276
+ // autoOpen: false, // Automatically open panel on load
277
+ // autoConnect: false, // Automatically connect on load
278
+ // showWelcomeMessage: true,
279
+ // welcomeMessage: 'Hello! How can I help you today?'
280
+ // },
136
281
 
282
+ // Accessibility Configuration
283
+ // accessibility: {
284
+ // ariaLabel: 'Voice Assistant',
285
+ // ariaDescription: 'Click to open voice assistant',
286
+ // keyboardNavigation: true // ESC key to close
287
+ // },
288
+
289
+ // Custom CSS
290
+ // customStyles: `
291
+ // #agent-widget {
292
+ // /* Your custom CSS here */
293
+ // }
294
+ // `,
295
+
296
+ // Variables for your agent/backend
137
297
  variables: {
138
298
  testMode: true,
139
299
  userName: 'Test User',
140
300
  page: 'test-agent-app.html'
141
- },
142
-
143
- primaryColor: '#10B981',
144
- position: 'bottom-right'
145
- });
301
+ }
302
+ });</code></pre></div>
146
303
  </div>
304
+
305
+ <script>
306
+ function switchTab(tabName) {
307
+ // Hide all tab contents
308
+ document.querySelectorAll('.tab-content').forEach(content => {
309
+ content.classList.remove('active');
310
+ });
311
+
312
+ // Remove active class from all tabs
313
+ document.querySelectorAll('.tab').forEach(tab => {
314
+ tab.classList.remove('active');
315
+ });
316
+
317
+ // Show selected tab content
318
+ document.getElementById(tabName + '-tab').classList.add('active');
319
+
320
+ // Add active class to clicked tab
321
+ event.target.classList.add('active');
322
+ }
323
+ </script>
147
324
 
148
325
  <h2>Manual Tests:</h2>
149
326
  <button onclick="testMicButton()">Test Mic Button Click</button>
@@ -153,7 +330,7 @@ const widget = new TTPAgentSDK.AgentWidget({
153
330
  </div>
154
331
 
155
332
  <!-- Load the widget -->
156
- <script src="../agent-widget.js?v=24" onload="console.log('SDK script loaded successfully')" onerror="console.error('Failed to load SDK script')"></script>
333
+ <script src="../agent-widget.js" onload="console.log('SDK script loaded successfully')" onerror="console.error('Failed to load SDK script')"></script>
157
334
 
158
335
  <script>
159
336
  // Override console.log to show in page
@@ -200,36 +377,16 @@ const widget = new TTPAgentSDK.AgentWidget({
200
377
  }
201
378
 
202
379
  // Create a new AgentWidget instance with agent ID + app ID
203
- // Now supports extensive customization with sensible defaults!
204
- // You can customize: icon, button, position, header, messages, animation, behavior, accessibility
380
+ // getSessionUrl is now OPTIONAL - widget will auto-construct URL from agentId/appId
205
381
  const widget = new TTPAgentSDK.AgentWidget({
206
382
  agentId: 'agent_87c4a55a1',
207
383
  appId: 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC',
208
384
 
209
- // Direct connection without signed link
210
- getSessionUrl: async ({ agentId, appId, variables }) => {
211
- console.log('Creating direct session URL for agent:', agentId);
212
- console.log('App ID:', appId);
213
- console.log('Variables:', variables);
214
-
215
- updateStatus('Creating direct session URL...', 'info');
216
-
217
- try {
218
- // Direct WebSocket URL construction with demo flag
219
- const wsUrl = `wss://speech.talktopc.com/ws/conv?agentId=${agentId}&appId=${appId}&demo=true`;
220
-
221
- console.log('Generated direct session URL:', wsUrl);
222
- updateStatus('Direct session URL created βœ“', 'success');
223
-
224
- return wsUrl;
225
- } catch (error) {
226
- console.error('Failed to create direct session URL:', error);
227
- updateStatus('Failed to create direct session URL βœ—', 'error');
228
- throw error;
229
- }
230
- },
385
+ // getSessionUrl is OPTIONAL - omitted here, so widget auto-constructs the WebSocket URL
386
+ // If you need signed links or custom URL logic, you can provide it:
387
+ // getSessionUrl: async ({ agentId, appId, variables }) => { ... }
231
388
 
232
- // Pass some test variables
389
+ // Optional: Pass variables for your agent/backend
233
390
  variables: {
234
391
  testMode: true,
235
392
  userName: 'Test User',
@@ -237,9 +394,17 @@ const widget = new TTPAgentSDK.AgentWidget({
237
394
  connectionType: 'direct'
238
395
  },
239
396
 
240
- // Customize appearance
397
+ // Customize appearance (using simple config - backward compatible)
241
398
  primaryColor: '#10B981',
242
- position: 'bottom-right'
399
+ position: 'bottom-right',
400
+
401
+ // Enhanced features are now available but using defaults
402
+ // You can optionally add:
403
+ // icon: { type: 'emoji', emoji: '🎀', size: 'large' },
404
+ // button: { size: 'large', shape: 'circle' },
405
+ // panel: { width: 400, height: 600 },
406
+ // header: { title: 'My Voice Assistant' },
407
+ // animation: { enableHover: true, enablePulse: true }
243
408
  });
244
409
 
245
410
  // Store widget reference for testing (like the working implementation)
@@ -188,7 +188,9 @@ const widget = new TTPAgentSDK.AgentWidget({
188
188
  </div>
189
189
 
190
190
  <!-- Load the widget -->
191
- <script src="../dist/agent-widget.js" onload="console.log('SDK script loaded successfully')" onerror="console.error('Failed to load SDK script')"></script>
191
+ <script src="../agent-widget.js"
192
+ onload="console.log('Script loaded, checking TTPAgentSDK:', typeof window.TTPAgentSDK);"
193
+ onerror="console.error('Failed to load SDK script'); window.sdkLoadError = true;"></script>
192
194
 
193
195
  <script>
194
196
  // Override console.log to show in page
@@ -220,24 +222,52 @@ const widget = new TTPAgentSDK.AgentWidget({
220
222
  statusDiv.className = 'status ' + type;
221
223
  }
222
224
 
223
- // Initialize the widget
224
- try {
225
- console.log('Initializing widget with signed link...');
226
- console.log('TTPAgentSDK available:', typeof TTPAgentSDK);
227
- console.log('TTPAgentSDK.AgentWidget available:', typeof TTPAgentSDK?.AgentWidget);
225
+ // Wait for TTPAgentSDK to be available
226
+ function waitForSDK(callback, maxAttempts = 50) {
227
+ // Check if there was a load error
228
+ if (window.sdkLoadError) {
229
+ console.error('SDK script failed to load (check network tab)');
230
+ updateStatus('SDK script failed to load - check console for errors', 'error');
231
+ return;
232
+ }
228
233
 
229
- if (typeof TTPAgentSDK === 'undefined') {
230
- throw new Error('TTPAgentSDK is not defined. Check if the script loaded correctly.');
234
+ // Check if TTPAgentSDK is available
235
+ if (typeof window.TTPAgentSDK !== 'undefined' && window.TTPAgentSDK !== null) {
236
+ console.log('SDK script loaded successfully');
237
+ console.log('TTPAgentSDK type:', typeof window.TTPAgentSDK);
238
+ console.log('TTPAgentSDK keys:', Object.keys(window.TTPAgentSDK || {}).slice(0, 5));
239
+ callback();
240
+ return;
231
241
  }
232
242
 
233
- if (typeof TTPAgentSDK.AgentWidget === 'undefined') {
234
- throw new Error('TTPAgentSDK.AgentWidget is not defined. Check the SDK build.');
243
+ if (maxAttempts <= 0) {
244
+ console.error('SDK failed to load after timeout');
245
+ console.error('window.TTPAgentSDK:', window.TTPAgentSDK);
246
+ console.error('Check browser console and network tab for errors');
247
+ updateStatus('SDK failed to load after timeout - check console', 'error');
248
+ return;
235
249
  }
236
250
 
237
- // Create a new AgentWidget instance with signed link
238
- // Now supports extensive customization with sensible defaults!
239
- // You can customize: icon, button, position, header, messages, animation, behavior, accessibility
240
- const widget = new TTPAgentSDK.AgentWidget({
251
+ setTimeout(() => waitForSDK(callback, maxAttempts - 1), 100);
252
+ }
253
+
254
+ // Initialize the widget once SDK is loaded
255
+ waitForSDK(() => {
256
+ try {
257
+ console.log('Initializing widget with signed link...');
258
+ console.log('TTPAgentSDK available:', typeof window.TTPAgentSDK);
259
+ console.log('TTPAgentSDK.AgentWidget available:', typeof window.TTPAgentSDK?.AgentWidget);
260
+
261
+ if (typeof window.TTPAgentSDK === 'undefined') {
262
+ throw new Error('TTPAgentSDK is not defined. Check if the script loaded correctly.');
263
+ }
264
+
265
+ if (typeof window.TTPAgentSDK.AgentWidget === 'undefined') {
266
+ throw new Error('TTPAgentSDK.AgentWidget is not defined. Check the SDK build.');
267
+ }
268
+
269
+ // Create a new AgentWidget instance with signed link
270
+ const widget = new window.TTPAgentSDK.AgentWidget({
241
271
  agentId: 'agent_87c4a55a1',
242
272
  appId: 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC',
243
273
 
@@ -319,10 +349,11 @@ const widget = new TTPAgentSDK.AgentWidget({
319
349
  console.log('Test methods available at window.testWidget');
320
350
  updateStatus('Widget loaded and ready βœ“', 'success');
321
351
 
322
- } catch (error) {
323
- console.error('Failed to initialize widget:', error);
324
- updateStatus('Widget failed to load βœ—', 'error');
325
- }
352
+ } catch (error) {
353
+ console.error('Failed to initialize widget:', error);
354
+ updateStatus('Failed to initialize widget: ' + error.message, 'error');
355
+ }
356
+ });
326
357
 
327
358
  // Test functions (matching the working implementation)
328
359
  function testMicButton() {
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta http-equiv="refresh" content="0; url=test-agent-app.html">
6
+ <title>Redirecting to Test Page...</title>
7
+ <script>
8
+ // Immediate redirect
9
+ window.location.href = 'test-agent-app.html';
10
+ </script>
11
+ </head>
12
+ <body>
13
+ <p>If you are not redirected automatically, <a href="test-agent-app.html">click here</a>.</p>
14
+ </body>
15
+ </html>
16
+
package/dist/index.html CHANGED
@@ -167,7 +167,7 @@
167
167
  });
168
168
  &lt;/script&gt;
169
169
  </div>
170
- <a href="examples/test.html" class="demo-button">Try Widget Demo</a>
170
+ <a href="examples/test-agent-app.html" class="demo-button">Try Widget Demo</a>
171
171
  </div>
172
172
 
173
173
  <div class="card">