@smooai/smooth-operator 1.11.4 → 1.13.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.
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import type { ChatWidgetConfig, ChatWidgetMode, ChatWidgetTheme } from './config.js';
17
17
  import { resolveConfig } from './config.js';
18
- import { type ChatMessage, type Citation, type ConnectionStatus, ConversationController } from './conversation.js';
18
+ import { type ChatMessage, type ChatPrompt, type Citation, type ConnectionStatus, ConversationController } from './conversation.js';
19
19
  import { SMOOTH_LOGO_SVG } from './logo.js';
20
20
  import { buildStyles } from './styles.js';
21
21
 
@@ -271,6 +271,13 @@ export class SmoothAgentChatElement extends HTMLElement {
271
271
  }
272
272
  this.messagesEl.appendChild(el);
273
273
 
274
+ // Render chat-native button prompts (SEP ui/confirm + ui/select,
275
+ // projected from write_confirmation_required). The click resumes the
276
+ // paused turn via the controller.
277
+ if (msg.prompt) {
278
+ this.messagesEl.appendChild(this.renderPrompt(msg.prompt));
279
+ }
280
+
274
281
  // Render a "Sources (N)" section under any assistant message whose
275
282
  // terminal eventual_response carried citations. Back-compatible: most
276
283
  // turns have none, so this is skipped.
@@ -281,6 +288,47 @@ export class SmoothAgentChatElement extends HTMLElement {
281
288
  this.messagesEl.scrollTop = this.messagesEl.scrollHeight;
282
289
  }
283
290
 
291
+ /**
292
+ * Render a chat-native button prompt (SEP `ui/confirm` / `ui/select`). Each
293
+ * option is a button; clicking one resumes the paused turn via
294
+ * {@link ConversationController.answerPrompt}. Once answered the buttons
295
+ * disable and the chosen label is shown, so the record stays in the
296
+ * transcript. Built with DOM APIs (no innerHTML) — prompt text is untrusted.
297
+ */
298
+ private renderPrompt(prompt: ChatPrompt): HTMLElement {
299
+ const wrap = document.createElement('div');
300
+ wrap.className = 'prompt';
301
+ wrap.setAttribute('part', 'prompt');
302
+
303
+ const text = document.createElement('div');
304
+ text.className = 'prompt-text';
305
+ text.textContent = prompt.text;
306
+ wrap.appendChild(text);
307
+
308
+ if (prompt.answered) {
309
+ const chosen = document.createElement('div');
310
+ chosen.className = 'prompt-answered';
311
+ chosen.textContent = `You chose: ${prompt.answered}`;
312
+ wrap.appendChild(chosen);
313
+ return wrap;
314
+ }
315
+
316
+ const buttons = document.createElement('div');
317
+ buttons.className = 'prompt-buttons';
318
+ for (const opt of prompt.options) {
319
+ const btn = document.createElement('button');
320
+ btn.className = 'prompt-button';
321
+ btn.type = 'button';
322
+ btn.textContent = opt.label;
323
+ btn.addEventListener('click', () => {
324
+ this.controller?.answerPrompt(prompt.requestId, opt.value);
325
+ });
326
+ buttons.appendChild(btn);
327
+ }
328
+ wrap.appendChild(buttons);
329
+ return wrap;
330
+ }
331
+
284
332
  /**
285
333
  * Build the collapsible "Sources (N)" block for an assistant message's
286
334
  * citations. Each source renders its `title` (linked to `citation.url` when
@@ -168,6 +168,35 @@ export function buildStyles(theme: Required<ChatWidgetTheme>, mode: ChatWidgetMo
168
168
 
169
169
  /* Sources panel — rendered under an assistant bubble whose terminal
170
170
  eventual_response carried citations. */
171
+ .prompt {
172
+ align-self: flex-start;
173
+ max-width: 80%;
174
+ margin-top: -2px;
175
+ display: flex;
176
+ flex-direction: column;
177
+ gap: 8px;
178
+ }
179
+ .panel.fullpage .prompt { max-width: 100%; }
180
+ .prompt-text { font-size: 13.5px; color: var(--sac-text); opacity: 0.9; }
181
+ .prompt-buttons { display: flex; gap: 8px; flex-wrap: wrap; }
182
+ .prompt-button {
183
+ cursor: pointer;
184
+ border: 1px solid var(--sac-border);
185
+ background: var(--sac-bg);
186
+ color: var(--sac-text);
187
+ border-radius: 999px;
188
+ padding: 6px 16px;
189
+ font-size: 13px;
190
+ font-weight: 600;
191
+ transition: background 0.15s, color 0.15s, border-color 0.15s;
192
+ }
193
+ .prompt-button:hover {
194
+ background: var(--sac-primary);
195
+ color: var(--sac-primary-text);
196
+ border-color: var(--sac-primary);
197
+ }
198
+ .prompt-answered { font-size: 12.5px; opacity: 0.7; font-style: italic; }
199
+
171
200
  .sources {
172
201
  align-self: flex-start;
173
202
  max-width: 80%;