ttp-agent-sdk 2.39.0 β†’ 2.40.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.
@@ -316,6 +316,51 @@
316
316
  <span class="badge badge--new">E-Commerce</span>
317
317
  </div>
318
318
  </a>
319
+
320
+ <a href="../examples/test-pharma.html" class="test-card">
321
+ <span class="test-card__icon">πŸ’Š</span>
322
+ <h3 class="test-card__title">Pharma Widget Test</h3>
323
+ <p class="test-card__description">
324
+ Test the pharmacy flavor β€” medication search, prescription management,
325
+ and medication cards with Rx/OTC badges. Simulate show_items and
326
+ prescription_updated messages without a live voice call.
327
+ </p>
328
+ <div class="test-card__badges">
329
+ <span class="badge badge--widget">Widget</span>
330
+ <span class="badge badge--voice">Voice</span>
331
+ <span class="badge badge--new">Pharma</span>
332
+ </div>
333
+ </a>
334
+
335
+ <a href="../examples/test-restaurant.html" class="test-card">
336
+ <span class="test-card__icon">🍽️</span>
337
+ <h3 class="test-card__title">Restaurant Widget Test</h3>
338
+ <p class="test-card__description">
339
+ Test the restaurant flavor β€” menu search, order management, menu item cards
340
+ with allergen/dietary tags, and photo gallery. Simulate show_items,
341
+ order_updated, and show_media messages without a live voice call.
342
+ </p>
343
+ <div class="test-card__badges">
344
+ <span class="badge badge--widget">Widget</span>
345
+ <span class="badge badge--voice">Voice</span>
346
+ <span class="badge badge--new">Restaurant</span>
347
+ </div>
348
+ </a>
349
+
350
+ <a href="../examples/test-tour.html" class="test-card">
351
+ <span class="test-card__icon">πŸ—ΊοΈ</span>
352
+ <h3 class="test-card__title">Tour Widget Test</h3>
353
+ <p class="test-card__description">
354
+ Test the tours flavor β€” tour search, booking management, tour cards
355
+ with activity tags, and photo gallery. Simulate show_items,
356
+ cart_updated, and show_media messages without a live voice call.
357
+ </p>
358
+ <div class="test-card__badges">
359
+ <span class="badge badge--widget">Widget</span>
360
+ <span class="badge badge--voice">Voice</span>
361
+ <span class="badge badge--new">Tours</span>
362
+ </div>
363
+ </a>
319
364
  </div>
320
365
  </div>
321
366
 
@@ -138,7 +138,11 @@
138
138
  <div class="settings-grid">
139
139
  <label>Agent
140
140
  <select id="agentSelect" onchange="handleAgentChange()">
141
- <option value="agent_d0774f1af|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo">Hotels Demo (agent_d0774f1af)</option>
141
+ <option value="agent_ed18369b3|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|ecommerce|mock-store">Ecommerce Demo (agent_ed18369b3)</option>
142
+ <option value="agent_d0774f1af|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|hotels|mock-hotel" selected>Hotels Demo (agent_d0774f1af)</option>
143
+ <option value="agent_PHARMA_ID|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|pharma|mock-pharm">Pharma Demo (update agent ID)</option>
144
+ <option value="agent_RESTAURANT_ID|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|restaurants|mock-restaurant">Restaurant Demo (update agent ID)</option>
145
+ <option value="agent_TOUR_ID|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|tours|mock-tour">Tour Demo (update agent ID)</option>
142
146
  <option value="custom">Custom...</option>
143
147
  </select>
144
148
  </label>
@@ -160,17 +164,19 @@
160
164
  <option value="rtl">RTL</option>
161
165
  </select>
162
166
  </label>
163
- <label>Widget Mode
164
- <select id="modeSelect">
165
- <option value="unified" selected>Unified (Both)</option>
166
- <option value="voice-only">Voice Only</option>
167
- <option value="text-only">Text Only</option>
167
+ <label>STT Provider
168
+ <select id="sttSelect">
169
+ <option value="">Default (server)</option>
170
+ <option value="azure-stt" selected>Azure STT</option>
171
+ <option value="cartesia-stt">Cartesia (Ink-Whisper)</option>
172
+ <option value="openai-realtime">OpenAI Realtime</option>
173
+ <option value="soniox">Soniox</option>
168
174
  </select>
169
175
  </label>
170
176
  <label>Start Open
171
177
  <select id="startOpenSelect">
172
- <option value="true" selected>Yes</option>
173
- <option value="false">No</option>
178
+ <option value="true">Yes</option>
179
+ <option value="false" selected>No</option>
174
180
  </select>
175
181
  </label>
176
182
  </div>
@@ -267,11 +273,13 @@ window.testWidget._flavor.messageHandlers['show_media']({
267
273
  if (sel.value === 'custom') {
268
274
  return {
269
275
  agentId: document.getElementById('customAgentId').value,
270
- appId: document.getElementById('customAppId').value
276
+ appId: document.getElementById('customAppId').value,
277
+ flavorType: 'ecommerce',
278
+ partnerId: 'mock-store'
271
279
  };
272
280
  }
273
- const [agentId, appId] = sel.value.split('|');
274
- return { agentId, appId };
281
+ const [agentId, appId, flavorType, partnerId] = sel.value.split('|');
282
+ return { agentId, appId, flavorType, partnerId };
275
283
  }
276
284
 
277
285
  function createWidget() {
@@ -293,24 +301,34 @@ window.testWidget._flavor.messageHandlers['show_media']({
293
301
  appId: agent.appId,
294
302
  language: document.getElementById('languageSelect').value,
295
303
  direction: document.getElementById('dirSelect').value,
304
+ agentSettingsOverride: (() => {
305
+ const override = {};
306
+ const stt = document.getElementById('sttSelect').value;
307
+ if (stt) override.sttProvider = stt;
308
+ return override;
309
+ })(),
296
310
  behavior: {
297
- mode: document.getElementById('modeSelect').value,
298
311
  startOpen: document.getElementById('startOpenSelect').value === 'true'
299
312
  },
300
313
  flavor: {
301
- type: 'hotels',
302
- partnerId: 'mock-hotel'
314
+ type: agent.flavorType,
315
+ partnerId: agent.partnerId
303
316
  },
304
317
  icon: {
305
318
  type: 'custom',
306
319
  customImage: 'https://talktopc.com/logo192.png',
307
320
  size: 'medium',
308
321
  backgroundColor: '#FFFFFF'
322
+ },
323
+ whatsapp: {
324
+ number: '+972508665824',
325
+ text: 'Χ”Χ™Χ™, ΧΧ©ΧžΧ— אם ΧͺΧ•Χ›ΧœΧ™ ΧœΧ’Χ–Χ•Χ¨ ΧœΧ™ '
309
326
  }
310
327
  });
311
328
 
312
329
  window.testWidget = chatWidget;
313
- updateStatus('TTPChatWidget created with hotels flavor (partnerId: mock-hotel)', 'success');
330
+ const sttLabel = document.getElementById('sttSelect').selectedOptions[0].text;
331
+ updateStatus('TTPChatWidget created β€” ' + agent.flavorType + ' flavor (' + agent.partnerId + '), STT: ' + sttLabel, 'success');
314
332
  }
315
333
 
316
334
  // Button handlers
@@ -0,0 +1,376 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
+ <title>TTP Tour Flavor - Test</title>
7
+ <style>
8
+ body {
9
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
10
+ max-width: 1200px;
11
+ margin: 40px auto;
12
+ padding: 20px;
13
+ background: #F9FAFB;
14
+ }
15
+
16
+ .container {
17
+ background: white;
18
+ padding: 30px;
19
+ border-radius: 12px;
20
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
21
+ }
22
+
23
+ h1 { color: #111827; margin-top: 0; }
24
+ h2 { color: #374151; border-bottom: 2px solid #E5E7EB; padding-bottom: 8px; margin-top: 30px; }
25
+
26
+ .info {
27
+ background: #EFF6FF;
28
+ border-left: 4px solid #3B82F6;
29
+ padding: 16px;
30
+ margin: 20px 0;
31
+ border-radius: 4px;
32
+ }
33
+
34
+ .status {
35
+ margin: 20px 0;
36
+ padding: 12px;
37
+ background: #F3F4F6;
38
+ border-radius: 6px;
39
+ font-family: monospace;
40
+ font-size: 14px;
41
+ }
42
+ .status.success { background: #D1FAE5; color: #065F46; }
43
+ .status.error { background: #FEE2E2; color: #991B1B; }
44
+
45
+ button {
46
+ background: #2563EB;
47
+ color: white;
48
+ border: none;
49
+ padding: 12px 24px;
50
+ border-radius: 6px;
51
+ cursor: pointer;
52
+ font-size: 16px;
53
+ margin: 10px 10px 10px 0;
54
+ }
55
+ button:hover { background: #1D4ED8; }
56
+ button.secondary { background: #6B7280; }
57
+ button.secondary:hover { background: #4B5563; }
58
+ button.success { background: #059669; }
59
+ button.success:hover { background: #047857; }
60
+
61
+ label {
62
+ display: flex;
63
+ flex-direction: column;
64
+ gap: 4px;
65
+ font-size: 14px;
66
+ color: #374151;
67
+ }
68
+
69
+ select, input[type="text"] {
70
+ padding: 8px 12px;
71
+ border: 1px solid #D1D5DB;
72
+ border-radius: 6px;
73
+ font-size: 14px;
74
+ font-family: inherit;
75
+ background: white;
76
+ color: #111827;
77
+ }
78
+
79
+ .settings-grid {
80
+ display: grid;
81
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
82
+ gap: 16px;
83
+ margin: 16px 0;
84
+ }
85
+
86
+ .test-section {
87
+ border: 1px solid #E5E7EB;
88
+ border-radius: 8px;
89
+ padding: 20px;
90
+ margin: 16px 0;
91
+ background: #F9FAFB;
92
+ }
93
+
94
+ .test-section h3 {
95
+ margin: 0 0 12px 0;
96
+ color: #111827;
97
+ }
98
+
99
+ .code-block {
100
+ background: #1F2937;
101
+ color: #F9FAFB;
102
+ padding: 16px;
103
+ border-radius: 6px;
104
+ font-family: monospace;
105
+ font-size: 12px;
106
+ overflow-x: auto;
107
+ margin: 20px 0;
108
+ white-space: pre-wrap;
109
+ }
110
+
111
+ @media (max-width: 768px) {
112
+ body { margin: 0; padding: 10px; }
113
+ .container { padding: 16px; border-radius: 8px; }
114
+ h1 { font-size: 24px; }
115
+ button { width: 100%; margin: 8px 0; }
116
+ .settings-grid { grid-template-columns: 1fr; }
117
+ }
118
+ </style>
119
+ </head>
120
+ <body>
121
+ <div class="container">
122
+ <h1>TTP Tour Flavor Test</h1>
123
+
124
+ <div class="info">
125
+ <strong>How it works:</strong>
126
+ <ul>
127
+ <li>Uses <code>TTPChatWidget</code> with <code>flavor: { type: 'tours', partnerId: 'mock-tour' }</code></li>
128
+ <li>The backend injects tour tools (<code>search_tours</code>, <code>book_tour</code>, <code>get_tour_booking</code>, <code>show_media</code>)</li>
129
+ <li>Tour cards display when the agent sends <code>show_items</code> messages</li>
130
+ <li>Booking summary updates on <code>cart_updated</code> messages</li>
131
+ <li>Gallery (<code>show_media</code>) opens fullscreen for tour photos, highlights, etc.</li>
132
+ </ul>
133
+ </div>
134
+
135
+ <div id="status" class="status">Loading SDK...</div>
136
+
137
+ <h2>Widget Configuration</h2>
138
+ <div class="settings-grid">
139
+ <label>Agent ID
140
+ <input id="agentId" type="text" value="agent_b8f001773" placeholder="agent_..." />
141
+ </label>
142
+ <label>App ID
143
+ <input id="appId" type="text" value="app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo" placeholder="app_..." />
144
+ </label>
145
+ <label>Language
146
+ <select id="languageSelect">
147
+ <option value="en" selected>English</option>
148
+ </select>
149
+ </label>
150
+ <label>STT Provider
151
+ <select id="sttSelect">
152
+ <option value="">Default (server)</option>
153
+ <option value="azure-stt" selected>Azure STT</option>
154
+ </select>
155
+ </label>
156
+ </div>
157
+
158
+ <div style="margin-top: 16px;">
159
+ <button id="createBtn">Create Widget</button>
160
+ <button id="destroyBtn" class="secondary">Destroy Widget</button>
161
+ </div>
162
+
163
+ <h2>Test Actions (Simulated Messages)</h2>
164
+
165
+ <div class="test-section">
166
+ <h3>Show Tour Items</h3>
167
+ <p style="color: #6B7280; font-size: 14px; margin-bottom: 12px;">
168
+ Injects a <code>show_items</code> message with mock tour packages.
169
+ </p>
170
+ <button id="showToursBtn" class="success">Show Tour Items</button>
171
+ </div>
172
+
173
+ <div class="test-section">
174
+ <h3>Show Gallery</h3>
175
+ <p style="color: #6B7280; font-size: 14px; margin-bottom: 12px;">
176
+ Injects a <code>show_media</code> message to test fullscreen gallery with tour photos.
177
+ </p>
178
+ <button id="showGalleryBtn" class="success">Show Gallery</button>
179
+ </div>
180
+
181
+ <div class="test-section">
182
+ <h3>Booking Updated</h3>
183
+ <p style="color: #6B7280; font-size: 14px; margin-bottom: 12px;">
184
+ Injects a <code>cart_updated</code> message to test the booking summary bar.
185
+ </p>
186
+ <button id="bookingBtn" class="success">Simulate Booking</button>
187
+ <button id="clearBookingBtn" class="secondary">Clear Booking</button>
188
+ </div>
189
+
190
+ <h2>Console Commands</h2>
191
+ <div class="code-block">// Access the widget instance
192
+ window.testWidget
193
+
194
+ // Inject messages manually
195
+ window.testWidget._flavor.messageHandlers['show_items']({
196
+ t: 'show_items',
197
+ items: [
198
+ { id: 'TOUR-001', name: 'Old City Walking Tour', category: 'Walking Tours', price: 49.99, currency: 'USD', imageUrl: '...', available: true, tags: ['walking', 'history'], description: '3-hour guided walking tour' }
199
+ ],
200
+ title: 'Available Tours'
201
+ });</div>
202
+ </div>
203
+
204
+ <script>
205
+ (function() {
206
+ var isNgrok = window.location.hostname.includes('ngrok');
207
+ if (isNgrok) {
208
+ var s = document.createElement('script');
209
+ s.type = 'text/javascript';
210
+ document.head.appendChild(s);
211
+ fetch('/agent-widget.js', { headers: { 'ngrok-skip-browser-warning': '1' } })
212
+ .then(function(r) { return r.text(); })
213
+ .then(function(code) { s.textContent = code; })
214
+ .catch(function(e) { console.error('SDK fetch failed:', e); });
215
+ } else {
216
+ var s = document.createElement('script');
217
+ s.src = '/agent-widget.js';
218
+ document.head.appendChild(s);
219
+ }
220
+ })();
221
+ </script>
222
+
223
+ <script>
224
+ let chatWidget = null;
225
+
226
+ function updateStatus(msg, type = '') {
227
+ const el = document.getElementById('status');
228
+ el.textContent = msg;
229
+ el.className = 'status ' + type;
230
+ }
231
+
232
+ function createWidget() {
233
+ if (chatWidget) {
234
+ chatWidget.destroy();
235
+ chatWidget = null;
236
+ }
237
+
238
+ const TTPAgentSDK = window.TTPAgentSDK;
239
+ if (!TTPAgentSDK || !TTPAgentSDK.TTPChatWidget) {
240
+ updateStatus('TTPChatWidget not available in SDK', 'error');
241
+ return;
242
+ }
243
+
244
+ const agentId = document.getElementById('agentId').value;
245
+ const appId = document.getElementById('appId').value;
246
+
247
+ chatWidget = new TTPAgentSDK.TTPChatWidget({
248
+ agentId,
249
+ appId,
250
+ language: document.getElementById('languageSelect').value,
251
+ agentSettingsOverride: (() => {
252
+ const override = {};
253
+ const stt = document.getElementById('sttSelect').value;
254
+ if (stt) override.sttProvider = stt;
255
+ return override;
256
+ })(),
257
+ behavior: {
258
+ mode: 'unified',
259
+ startOpen: true
260
+ },
261
+ flavor: {
262
+ type: 'tours',
263
+ partnerId: 'mock-tour'
264
+ },
265
+ icon: {
266
+ type: 'custom',
267
+ customImage: 'https://talktopc.com/logo192.png',
268
+ size: 'medium',
269
+ backgroundColor: '#FFFFFF'
270
+ },
271
+ whatsapp: {
272
+ number: '+972508665824',
273
+ text: 'Χ”Χ™Χ™, ΧΧ©ΧžΧ— אם ΧͺΧ•Χ›ΧœΧ™ ΧœΧ’Χ–Χ•Χ¨ ΧœΧ™ Χ‘ΧžΧ©Χ”Χ•....'
274
+ }
275
+ });
276
+
277
+ window.testWidget = chatWidget;
278
+ updateStatus('TTPChatWidget created β€” tours flavor (mock-tour)', 'success');
279
+ }
280
+
281
+ document.getElementById('createBtn').onclick = createWidget;
282
+
283
+ document.getElementById('destroyBtn').onclick = () => {
284
+ if (chatWidget) {
285
+ chatWidget.destroy();
286
+ chatWidget = null;
287
+ updateStatus('Widget destroyed', '');
288
+ }
289
+ };
290
+
291
+ document.getElementById('showToursBtn').onclick = () => {
292
+ if (!chatWidget || !chatWidget._flavor) {
293
+ updateStatus('Create widget first', 'error');
294
+ return;
295
+ }
296
+ chatWidget._flavor.messageHandlers['show_items']({
297
+ t: 'show_items',
298
+ items: [
299
+ { id: 'TOUR-001', name: 'Old City Walking Tour', category: 'Walking Tours', price: 49.99, currency: 'USD', imageUrl: 'https://images.unsplash.com/photo-1467269204594-9661b134dd2b?w=300&h=300&fit=crop', available: true, tags: ['walking', 'history', 'culture'], description: '3-hour guided tour through ancient streets and landmarks' },
300
+ { id: 'TOUR-002', name: 'Sunset Kayak Adventure', category: 'Water Activities', price: 79.99, currency: 'USD', imageUrl: 'https://images.unsplash.com/photo-1472745942893-4b9f730c7668?w=300&h=300&fit=crop', available: true, tags: ['water', 'adventure', 'sunset'], description: '2-hour kayaking experience with stunning sunset views' },
301
+ { id: 'TOUR-003', name: 'Mountain Hiking Expedition', category: 'Hiking', price: 89.99, currency: 'USD', imageUrl: 'https://images.unsplash.com/photo-1551632811-561732d1e306?w=300&h=300&fit=crop', available: true, tags: ['hiking', 'nature', 'mountain'], description: 'Full-day guided hike through scenic mountain trails' },
302
+ { id: 'TOUR-004', name: 'Food & Wine Tasting Tour', category: 'Food Tours', price: 64.99, currency: 'USD', imageUrl: 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=300&h=300&fit=crop', available: true, tags: ['food', 'wine', 'tasting'], description: 'Sample local cuisine and wines at 5 curated stops' }
303
+ ],
304
+ title: '4 tours found'
305
+ });
306
+ updateStatus('show_items injected with 4 tour packages', 'success');
307
+ };
308
+
309
+ document.getElementById('showGalleryBtn').onclick = () => {
310
+ if (!chatWidget || !chatWidget._flavor) {
311
+ updateStatus('Create widget first', 'error');
312
+ return;
313
+ }
314
+ chatWidget._flavor.messageHandlers['show_media']({
315
+ t: 'show_media',
316
+ images: [
317
+ { url: 'https://images.unsplash.com/photo-1469854523086-cc02fe5d8800?w=800', caption: 'Scenic road trip through the countryside' },
318
+ { url: 'https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?w=800', caption: 'Crystal clear lake adventure' },
319
+ { url: 'https://images.unsplash.com/photo-1530789253388-582c481c54b0?w=800', caption: 'Historic architecture tour' },
320
+ { url: 'https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=800', caption: 'Breathtaking mountain viewpoint' }
321
+ ],
322
+ title: 'Tour Highlights'
323
+ });
324
+ updateStatus('show_media injected with 4 images (fullscreen gallery)', 'success');
325
+ };
326
+
327
+ document.getElementById('bookingBtn').onclick = () => {
328
+ if (!chatWidget || !chatWidget._flavor) {
329
+ updateStatus('Create widget first', 'error');
330
+ return;
331
+ }
332
+ chatWidget._flavor.messageHandlers['cart_updated']({
333
+ t: 'cart_updated',
334
+ cartItemCount: 2,
335
+ cartTotal: 129.98,
336
+ action: 'added',
337
+ product: { id: 'TOUR-001', name: 'Old City Walking Tour', price: 49.99 }
338
+ });
339
+ updateStatus('cart_updated injected (2 tours, $129.98)', 'success');
340
+ };
341
+
342
+ document.getElementById('clearBookingBtn').onclick = () => {
343
+ if (!chatWidget || !chatWidget._flavor) {
344
+ updateStatus('Create widget first', 'error');
345
+ return;
346
+ }
347
+ chatWidget._flavor.messageHandlers['cart_updated']({
348
+ t: 'cart_updated',
349
+ cartItemCount: 0,
350
+ cartTotal: 0,
351
+ action: 'refreshed'
352
+ });
353
+ updateStatus('Booking cleared', '');
354
+ };
355
+
356
+ function waitForSDK() {
357
+ return new Promise((resolve, reject) => {
358
+ if (window.TTPAgentSDK?.TTPChatWidget) { resolve(); return; }
359
+ let attempts = 0;
360
+ const iv = setInterval(() => {
361
+ attempts++;
362
+ if (window.TTPAgentSDK?.TTPChatWidget) { clearInterval(iv); resolve(); }
363
+ else if (attempts >= 150) { clearInterval(iv); reject(new Error('SDK failed to load')); }
364
+ }, 100);
365
+ });
366
+ }
367
+
368
+ waitForSDK().then(() => {
369
+ updateStatus('SDK loaded β€” creating widget...', '');
370
+ createWidget();
371
+ }).catch(e => {
372
+ updateStatus('SDK load failed: ' + e.message, 'error');
373
+ });
374
+ </script>
375
+ </body>
376
+ </html>