@happyvertical/smrt-chat 0.51.38 → 0.52.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 (62) hide show
  1. package/AGENTS.md +19 -2
  2. package/README.md +13 -0
  3. package/dist/assistant-turn-events.d.ts +152 -0
  4. package/dist/assistant-turn-events.d.ts.map +1 -0
  5. package/dist/assistant-turn-events.js +2 -0
  6. package/dist/assistant-turn.d.ts +236 -0
  7. package/dist/assistant-turn.d.ts.map +1 -0
  8. package/dist/chunks/{ChatService-D48KBDZy.js → ChatService-jJi2JJJi.js} +2 -2
  9. package/dist/chunks/ChatService-jJi2JJJi.js.map +1 -0
  10. package/dist/chunks/assistant-turn-events-BbZUf-Ju.js +77 -0
  11. package/dist/chunks/assistant-turn-events-BbZUf-Ju.js.map +1 -0
  12. package/dist/index.d.ts +3 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +776 -104
  15. package/dist/index.js.map +1 -1
  16. package/dist/internal/agent-runtime.js +1 -1
  17. package/dist/manifest.json +6 -2
  18. package/dist/models/AgentSession.d.ts +11 -1
  19. package/dist/models/AgentSession.d.ts.map +1 -1
  20. package/dist/smrt-knowledge.json +7 -13
  21. package/dist/svelte/components/assistant/AssistantChoiceCards.svelte +309 -0
  22. package/dist/svelte/components/assistant/AssistantChoiceCards.svelte.d.ts +19 -0
  23. package/dist/svelte/components/assistant/AssistantChoiceCards.svelte.d.ts.map +1 -0
  24. package/dist/svelte/components/assistant/AssistantComposer.svelte +116 -14
  25. package/dist/svelte/components/assistant/AssistantComposer.svelte.d.ts +28 -0
  26. package/dist/svelte/components/assistant/AssistantComposer.svelte.d.ts.map +1 -1
  27. package/dist/svelte/components/assistant/AssistantDock.svelte +196 -1
  28. package/dist/svelte/components/assistant/AssistantDock.svelte.d.ts +38 -1
  29. package/dist/svelte/components/assistant/AssistantDock.svelte.d.ts.map +1 -1
  30. package/dist/svelte/components/assistant/AssistantThreadList.svelte +13 -1
  31. package/dist/svelte/components/assistant/__tests__/AssistantDock.test.js +16 -16
  32. package/dist/svelte/components/assistant/__tests__/assistant-composer-dictation.test.js +197 -0
  33. package/dist/svelte/components/assistant/__tests__/assistant-dock-choices-pending.test.js +224 -0
  34. package/dist/svelte/components/assistant/__tests__/assistant-dock-choices-preview.test.js +312 -0
  35. package/dist/svelte/components/assistant/__tests__/assistant-dock-choices.test.js +338 -0
  36. package/dist/svelte/components/assistant/__tests__/assistant-dock-client-tools.test.js +442 -0
  37. package/dist/svelte/components/assistant/__tests__/assistant-dock-run.test.js +303 -0
  38. package/dist/svelte/components/assistant/__tests__/assistant-dock-settle.test.js +146 -0
  39. package/dist/svelte/components/assistant/assistant-choices.svelte.d.ts +251 -0
  40. package/dist/svelte/components/assistant/assistant-choices.svelte.d.ts.map +1 -0
  41. package/dist/svelte/components/assistant/assistant-choices.svelte.js +520 -0
  42. package/dist/svelte/components/assistant/assistant-transport.d.ts +54 -1
  43. package/dist/svelte/components/assistant/assistant-transport.d.ts.map +1 -1
  44. package/dist/svelte/components/assistant/assistant-transport.js +64 -0
  45. package/dist/svelte/components/assistant/client-tools.d.ts +85 -0
  46. package/dist/svelte/components/assistant/client-tools.d.ts.map +1 -0
  47. package/dist/svelte/components/assistant/client-tools.js +61 -0
  48. package/dist/svelte/components/assistant/create-assistant-dock-controller.svelte.d.ts +159 -0
  49. package/dist/svelte/components/assistant/create-assistant-dock-controller.svelte.d.ts.map +1 -1
  50. package/dist/svelte/components/assistant/create-assistant-dock-controller.svelte.js +0 -0
  51. package/dist/svelte/i18n.d.ts +15 -0
  52. package/dist/svelte/i18n.d.ts.map +1 -1
  53. package/dist/svelte/i18n.js +17 -1
  54. package/dist/svelte/index.d.ts +6 -2
  55. package/dist/svelte/index.d.ts.map +1 -1
  56. package/dist/svelte/index.js +8 -1
  57. package/dist/tool-allow-list.d.ts +8 -0
  58. package/dist/tool-allow-list.d.ts.map +1 -0
  59. package/dist/tool-loop.d.ts +191 -3
  60. package/dist/tool-loop.d.ts.map +1 -1
  61. package/package.json +19 -15
  62. package/dist/chunks/ChatService-D48KBDZy.js.map +0 -1
@@ -0,0 +1,520 @@
1
+ /**
2
+ * Choices: the assistant offers 1–4 options, the person picks one.
3
+ *
4
+ * The proposal counterpart of `assistant_propose_action` for work that has
5
+ * several good answers — "crop this tighter", "find me a picture of the
6
+ * arena". The page registers a {@link AssistantChoiceSource} while it can
7
+ * serve one; the dock offers each source to the model as a browser tool
8
+ * (`assistant_offer_<source id>`, effect `read`). When the model calls it the
9
+ * dock asks the SOURCE for the options (the model never supplies them), shows
10
+ * them as cards in the chat, and returns only their ids and labels to the
11
+ * model. Nothing changes until the person clicks a card: only then does the
12
+ * dock call the source's `apply`, in the page, as the person. The model has
13
+ * no way to apply an option.
14
+ *
15
+ * Images on the cards are restricted to same-origin paths (`/…`), so a
16
+ * source cannot leak a signed provider URL and an injected prompt cannot make
17
+ * the dock load a remote address.
18
+ *
19
+ * Options that take a while (generated pictures) arrive later: the offer
20
+ * carries `pending`, the cards show "Making…" placeholders and the source's
21
+ * `fill` adds options as they finish. The person can pick any option that
22
+ * has arrived. Such an offer is not replaced by the person's next message
23
+ * (it cost real work); "None of these" stops it.
24
+ *
25
+ * Previewing: a source that implements `preview` shows a pick in place on
26
+ * the page WITHOUT applying it. A click on a card only previews (another
27
+ * click swaps the preview; the offer's `original` card shows the page as it
28
+ * was); nothing is committed until the person presses the offer's commit
29
+ * button (`commit`, which applies the previewed option and resolves the
30
+ * offer). Cancel (`cancel`), dismissing, clearing the conversation and
31
+ * disposing all restore the original. The model still only offers.
32
+ */
33
+ /** Tool-name prefix for choice sources (add `assistant_offer_*` to a server allow-list). */
34
+ export const ASSISTANT_CHOICE_TOOL_PREFIX = 'assistant_offer_';
35
+ /** At most this many options are shown for one offer. */
36
+ export const ASSISTANT_CHOICE_MAX_OPTIONS = 4;
37
+ const SOURCE_ID_PATTERN = /^[a-z][a-z0-9_]{0,39}$/;
38
+ /** A simple in-memory registry; the latest registration of an id wins. */
39
+ export function createAssistantChoiceSourceRegistry() {
40
+ // Raw: sources are host objects compared by identity, never deep-proxied.
41
+ let sources = $state.raw([]);
42
+ return {
43
+ register(source) {
44
+ if (!SOURCE_ID_PATTERN.test(source.id)) {
45
+ throw new Error(`Invalid choice source id "${source.id}"`);
46
+ }
47
+ sources = [...sources.filter((s) => s.id !== source.id), source];
48
+ return () => {
49
+ sources = sources.filter((s) => s !== source);
50
+ };
51
+ },
52
+ list() {
53
+ return sources;
54
+ },
55
+ };
56
+ }
57
+ /** The browser tool name for a source. */
58
+ export function choiceToolName(sourceId) {
59
+ return `${ASSISTANT_CHOICE_TOOL_PREFIX}${sourceId}`;
60
+ }
61
+ /** A same-origin path, or null. Rejects `//host`, `\\`, schemes, and controls. */
62
+ export function safeChoiceImageUrl(value) {
63
+ if (typeof value !== 'string')
64
+ return null;
65
+ const url = value.trim();
66
+ if (!/^\/(?![/\\])/.test(url))
67
+ return null;
68
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: rejecting control characters is the point
69
+ if (/[\u0000-\u001f\s\\]/.test(url))
70
+ return null;
71
+ return url;
72
+ }
73
+ function clean(value, max) {
74
+ return typeof value === 'string' ? value.trim().slice(0, max) : '';
75
+ }
76
+ /** Normalize a source's options: unique ids, plain labels, safe images, at most 4. */
77
+ export function normalizeChoiceOptions(options) {
78
+ const seen = new Set();
79
+ const result = [];
80
+ for (const option of options) {
81
+ const id = clean(option?.id, 120);
82
+ const label = clean(option?.label, 80);
83
+ if (!id || !label || seen.has(id))
84
+ continue;
85
+ seen.add(id);
86
+ const description = clean(option.description, 160);
87
+ const imageUrl = safeChoiceImageUrl(option.imageUrl);
88
+ result.push({
89
+ id,
90
+ label,
91
+ ...(description ? { description } : {}),
92
+ ...(imageUrl
93
+ ? { imageUrl, imageAlt: clean(option.imageAlt, 120) || label }
94
+ : {}),
95
+ ...(option.value !== undefined ? { value: option.value } : {}),
96
+ });
97
+ if (result.length >= ASSISTANT_CHOICE_MAX_OPTIONS)
98
+ break;
99
+ }
100
+ return result;
101
+ }
102
+ /** The dock's choice state: offers from tool calls, and the person's picks. */
103
+ export class AssistantChoices {
104
+ getRegistry;
105
+ hold;
106
+ sets = $state([]);
107
+ /** Release functions of the holds for offers still open. */
108
+ releases = new Map();
109
+ /**
110
+ * Per-offer preview queue and request counter: previews run one at a time
111
+ * in click order, so the page ends on the last click, and only the latest
112
+ * request updates the offer.
113
+ */
114
+ previewQueues = new Map();
115
+ previewRequests = new Map();
116
+ /** Abort controllers of pending offers still being filled. */
117
+ fills = new Map();
118
+ /**
119
+ * @param hold Called for each offer while it waits for the person (and
120
+ * after a failed apply); returns the release, called once they picked,
121
+ * dismissed, or the offer was replaced. The dock uses its run holds.
122
+ */
123
+ constructor(getRegistry, hold) {
124
+ this.getRegistry = getRegistry;
125
+ this.hold = hold;
126
+ }
127
+ /** Keep one hold per open offer (`waiting` or `failed`). */
128
+ syncHolds() {
129
+ const open = new Set(this.sets
130
+ .filter((set) => set.status === 'waiting' || set.status === 'failed')
131
+ .map((set) => set.id));
132
+ for (const [id, release] of this.releases) {
133
+ if (!open.has(id)) {
134
+ release();
135
+ this.releases.delete(id);
136
+ }
137
+ }
138
+ if (!this.hold)
139
+ return;
140
+ for (const set of this.sets) {
141
+ if (open.has(set.id) && !this.releases.has(set.id)) {
142
+ this.releases.set(set.id, this.hold(set));
143
+ }
144
+ }
145
+ }
146
+ sources() {
147
+ return (this.getRegistry()?.list() ?? []).filter((source) => SOURCE_ID_PATTERN.test(source.id));
148
+ }
149
+ source(id) {
150
+ return this.sources().find((source) => source.id === id);
151
+ }
152
+ /** The browser tools for the registered sources. */
153
+ tools() {
154
+ return this.sources().map((source) => ({
155
+ name: choiceToolName(source.id),
156
+ description: [
157
+ source.description.slice(0, 800),
158
+ 'Shows the options as cards in the chat; the person picks one and it is applied then. You cannot apply it yourself. Tell them to pick one.',
159
+ ].join('\n'),
160
+ inputSchema: source.inputSchema ?? {
161
+ type: 'object',
162
+ additionalProperties: false,
163
+ properties: {},
164
+ },
165
+ effect: 'read',
166
+ }));
167
+ }
168
+ isChoiceTool(name) {
169
+ return (name.startsWith(ASSISTANT_CHOICE_TOOL_PREFIX) &&
170
+ Boolean(this.source(name.slice(ASSISTANT_CHOICE_TOOL_PREFIX.length))));
171
+ }
172
+ /** Number of offers waiting for the person. */
173
+ get waitingCount() {
174
+ return this.sets.filter((set) => set.status === 'waiting').length;
175
+ }
176
+ /** The progress line of an offer still being made with nothing to pick yet. */
177
+ get pendingMessage() {
178
+ const making = this.sets.find((set) => set.status === 'waiting' && set.pending && set.options.length === 0);
179
+ return making?.pending?.message ?? null;
180
+ }
181
+ update(id, patch) {
182
+ this.sets = this.sets.map((set) => set.id === id ? { ...set, ...patch } : set);
183
+ this.syncHolds();
184
+ }
185
+ /** Run a model call to a choice tool: ask the source, show the cards. */
186
+ async offerFromCall(call, signal) {
187
+ const sourceId = call.name.slice(ASSISTANT_CHOICE_TOOL_PREFIX.length);
188
+ const source = this.source(sourceId);
189
+ if (!source)
190
+ return { id: call.id, ok: false, error: 'not_available' };
191
+ let offer;
192
+ try {
193
+ offer = await source.offer(call.args ?? {}, { signal });
194
+ }
195
+ catch (err) {
196
+ return {
197
+ id: call.id,
198
+ ok: false,
199
+ error: err instanceof Error ? err.message : String(err),
200
+ };
201
+ }
202
+ const pending = offer?.pending && typeof offer.pending.fill === 'function'
203
+ ? offer.pending
204
+ : null;
205
+ const options = normalizeChoiceOptions(offer?.options ?? []);
206
+ if (options.length === 0 && !pending) {
207
+ return { id: call.id, ok: false, error: 'Nothing to offer.' };
208
+ }
209
+ const pendingState = pending
210
+ ? {
211
+ message: clean(pending.message, 160) || 'Making options…',
212
+ expected: Math.min(ASSISTANT_CHOICE_MAX_OPTIONS - options.length, Math.max(1, Math.floor(Number(pending.expected) || 0) || 4)),
213
+ }
214
+ : undefined;
215
+ const previewable = typeof source.preview === 'function';
216
+ const original = previewable
217
+ ? normalizeChoiceOptions(offer?.original ? [offer.original] : [])[0]
218
+ : undefined;
219
+ const set = {
220
+ id: call.id,
221
+ sourceId,
222
+ title: clean(offer.title, 120) || 'Pick one',
223
+ options: options.filter((option) => option.id !== original?.id),
224
+ status: 'waiting',
225
+ ...(previewable
226
+ ? {
227
+ previewable: true,
228
+ ...(original ? { original } : {}),
229
+ commitLabel: clean(offer.commitLabel, 40) || 'Use this',
230
+ cancelLabel: clean(offer.cancelLabel, 40) || 'Cancel',
231
+ }
232
+ : {}),
233
+ ...(pendingState && pendingState.expected > 0
234
+ ? { pending: pendingState, lasting: true }
235
+ : {}),
236
+ };
237
+ this.sets = [...this.sets.filter((s) => s.id !== call.id), set];
238
+ this.syncHolds();
239
+ if (pending && set.pending)
240
+ this.fill(set.id, pending);
241
+ return {
242
+ id: call.id,
243
+ ok: true,
244
+ result: JSON.stringify({
245
+ offered: true,
246
+ waitingForUser: true,
247
+ ...(set.pending
248
+ ? { stillMaking: true, progress: set.pending.message }
249
+ : {}),
250
+ options: options.map(({ id, label }) => ({ id, label })),
251
+ }),
252
+ };
253
+ }
254
+ /** Run a pending offer's `fill`, adding its options as they finish. */
255
+ fill(setId, pending) {
256
+ const controller = new AbortController();
257
+ this.fills.get(setId)?.abort();
258
+ this.fills.set(setId, controller);
259
+ const live = () => !controller.signal.aborted
260
+ ? this.sets.find((s) => s.id === setId && s.status !== 'dismissed')
261
+ : undefined;
262
+ const update = {
263
+ add: (added) => {
264
+ const set = live();
265
+ if (!set)
266
+ return;
267
+ const options = normalizeChoiceOptions([
268
+ ...set.options,
269
+ ...(Array.isArray(added) ? added : []),
270
+ ]);
271
+ const remaining = set.pending
272
+ ? Math.max(0, Math.min(ASSISTANT_CHOICE_MAX_OPTIONS, set.options.length + set.pending.expected) - options.length)
273
+ : 0;
274
+ this.update(setId, {
275
+ options,
276
+ ...(set.pending
277
+ ? { pending: { ...set.pending, expected: remaining } }
278
+ : {}),
279
+ });
280
+ },
281
+ status: (message) => {
282
+ const set = live();
283
+ const text = clean(message, 160);
284
+ if (set?.pending && text) {
285
+ this.update(setId, { pending: { ...set.pending, message: text } });
286
+ }
287
+ },
288
+ };
289
+ const finish = (err) => {
290
+ if (this.fills.get(setId) === controller)
291
+ this.fills.delete(setId);
292
+ const set = live();
293
+ if (!set)
294
+ return;
295
+ const message = err == null
296
+ ? null
297
+ : (err instanceof Error ? err.message : String(err)).slice(0, 200);
298
+ if (set.options.length === 0) {
299
+ this.update(setId, {
300
+ status: 'unavailable',
301
+ pending: undefined,
302
+ error: message || 'Nothing came back. Try again.',
303
+ });
304
+ }
305
+ else {
306
+ this.update(setId, {
307
+ pending: undefined,
308
+ ...(message ? { note: message } : {}),
309
+ });
310
+ }
311
+ };
312
+ Promise.resolve()
313
+ .then(() => pending.fill(update, controller.signal))
314
+ .then(() => finish(null), (err) => finish(err ?? 'Nothing came back. Try again.'));
315
+ }
316
+ /** Stop filling an offer (it was picked, dismissed or cleared). */
317
+ stopFill(setId) {
318
+ this.fills.get(setId)?.abort();
319
+ this.fills.delete(setId);
320
+ }
321
+ /** The person picked `optionId`: apply it through its source. */
322
+ async choose(setId, optionId) {
323
+ const set = this.sets.find((s) => s.id === setId);
324
+ if (!set || (set.status !== 'waiting' && set.status !== 'failed'))
325
+ return;
326
+ const option = set.options.find((o) => o.id === optionId);
327
+ if (!option)
328
+ return;
329
+ const source = this.source(set.sourceId);
330
+ if (!source) {
331
+ this.update(setId, {
332
+ status: 'failed',
333
+ error: 'This is no longer on the page.',
334
+ });
335
+ return;
336
+ }
337
+ this.update(setId, {
338
+ status: 'applying',
339
+ chosenOptionId: optionId,
340
+ error: undefined,
341
+ });
342
+ try {
343
+ const outcome = await source.apply(option);
344
+ // Picked: versions still being made are no longer needed.
345
+ this.stopFill(setId);
346
+ this.update(setId, {
347
+ status: 'applied',
348
+ pending: undefined,
349
+ previewOptionId: undefined,
350
+ ...(typeof outcome === 'string' && outcome.trim()
351
+ ? { outcome: outcome.trim().slice(0, 200) }
352
+ : {}),
353
+ });
354
+ }
355
+ catch (err) {
356
+ this.update(setId, {
357
+ status: 'failed',
358
+ error: err instanceof Error ? err.message : String(err),
359
+ });
360
+ }
361
+ }
362
+ /** The person wants none of these. */
363
+ dismiss(setId) {
364
+ const set = this.sets.find((s) => s.id === setId);
365
+ if (set &&
366
+ (set.status === 'waiting' ||
367
+ set.status === 'failed' ||
368
+ set.status === 'unavailable')) {
369
+ this.stopFill(setId);
370
+ void this.restorePreview(setId);
371
+ this.update(setId, {
372
+ status: 'dismissed',
373
+ pending: undefined,
374
+ previewOptionId: undefined,
375
+ previewPendingId: undefined,
376
+ });
377
+ }
378
+ }
379
+ /**
380
+ * Put the page back if this offer is previewing something (or is about
381
+ * to). Queued behind any preview still running, and it cancels queued
382
+ * ones, so a slow preview never lands after the page was restored.
383
+ */
384
+ async restorePreview(setId) {
385
+ const set = this.sets.find((s) => s.id === setId);
386
+ if (!set?.previewable ||
387
+ (set.previewOptionId === undefined && set.previewPendingId === undefined)) {
388
+ return;
389
+ }
390
+ this.previewRequests.set(setId, (this.previewRequests.get(setId) ?? 0) + 1);
391
+ const { sourceId } = set;
392
+ const original = set.original ?? null;
393
+ const restore = async () => {
394
+ try {
395
+ await this.source(sourceId)?.preview?.(original);
396
+ }
397
+ catch {
398
+ // Nothing more to do: the page is leaving or the picture is gone.
399
+ }
400
+ };
401
+ const queued = (this.previewQueues.get(setId) ?? Promise.resolve()).then(restore);
402
+ this.previewQueues.set(setId, queued);
403
+ await queued;
404
+ }
405
+ /**
406
+ * The person clicked a card of a previewable offer (or its `original`):
407
+ * show it in place. Nothing is applied.
408
+ */
409
+ async preview(setId, optionId) {
410
+ const set = this.sets.find((s) => s.id === setId);
411
+ if (!set?.previewable ||
412
+ (set.status !== 'waiting' && set.status !== 'failed')) {
413
+ return;
414
+ }
415
+ const option = set.original?.id === optionId
416
+ ? set.original
417
+ : set.options.find((o) => o.id === optionId);
418
+ const source = this.source(set.sourceId);
419
+ if (!option || !source?.preview)
420
+ return;
421
+ const request = (this.previewRequests.get(setId) ?? 0) + 1;
422
+ this.previewRequests.set(setId, request);
423
+ const latest = () => this.previewRequests.get(setId) === request;
424
+ this.update(setId, { previewPendingId: optionId });
425
+ const run = async () => {
426
+ // A newer click (or a restore) is queued behind this one: let it run
427
+ // instead. A closed offer previews nothing.
428
+ const current = this.sets.find((s) => s.id === setId);
429
+ if (!latest() ||
430
+ !current ||
431
+ (current.status !== 'waiting' && current.status !== 'failed')) {
432
+ return;
433
+ }
434
+ // One preview at a time: put back any other offer's first.
435
+ for (const other of this.sets) {
436
+ if (other.id !== setId && other.previewOptionId !== undefined) {
437
+ await this.restorePreview(other.id);
438
+ this.update(other.id, { previewOptionId: undefined });
439
+ }
440
+ }
441
+ try {
442
+ await source.preview?.(option);
443
+ if (!latest())
444
+ return;
445
+ this.update(setId, {
446
+ status: 'waiting',
447
+ previewOptionId: optionId,
448
+ previewPendingId: undefined,
449
+ error: undefined,
450
+ });
451
+ }
452
+ catch (err) {
453
+ if (!latest())
454
+ return;
455
+ this.update(setId, {
456
+ status: 'failed',
457
+ previewPendingId: undefined,
458
+ error: err instanceof Error ? err.message : String(err),
459
+ });
460
+ }
461
+ };
462
+ const queued = (this.previewQueues.get(setId) ?? Promise.resolve()).then(run);
463
+ this.previewQueues.set(setId, queued);
464
+ await queued;
465
+ }
466
+ /**
467
+ * The person pressed the commit button: apply the previewed option (the
468
+ * one thing that changes the page). The original, or nothing, previewed
469
+ * means there is nothing to apply: that is a cancel.
470
+ */
471
+ async commit(setId) {
472
+ const set = this.sets.find((s) => s.id === setId);
473
+ // Never commit while a preview is still being shown: the option that
474
+ // would be applied is not yet the one on the page.
475
+ if (!set?.previewable || set.previewPendingId !== undefined)
476
+ return;
477
+ const id = set.previewOptionId;
478
+ if (!id || id === set.original?.id) {
479
+ this.cancel(setId);
480
+ return;
481
+ }
482
+ await this.choose(setId, id);
483
+ }
484
+ /** The person wants to keep the original: restore it and close the offer. */
485
+ cancel(setId) {
486
+ this.dismiss(setId);
487
+ }
488
+ /**
489
+ * A new request replaces offers still waiting, except ones that had
490
+ * options made for them (`lasting`): only the person dismisses those.
491
+ */
492
+ supersedeWaiting() {
493
+ if (this.waitingCount === 0)
494
+ return;
495
+ for (const set of this.sets) {
496
+ if (set.status === 'waiting' && !set.lasting) {
497
+ void this.restorePreview(set.id);
498
+ }
499
+ }
500
+ this.sets = this.sets.map((set) => set.status === 'waiting' && !set.lasting
501
+ ? {
502
+ ...set,
503
+ status: 'dismissed',
504
+ previewOptionId: undefined,
505
+ previewPendingId: undefined,
506
+ }
507
+ : set);
508
+ this.syncHolds();
509
+ }
510
+ clear() {
511
+ for (const controller of this.fills.values())
512
+ controller.abort();
513
+ this.fills.clear();
514
+ // An uncommitted preview never outlives the conversation.
515
+ for (const set of this.sets)
516
+ void this.restorePreview(set.id);
517
+ this.sets = [];
518
+ this.syncHolds();
519
+ }
520
+ }
@@ -37,6 +37,7 @@
37
37
  * intentionally line up with `ChatThreadData`/`ChatMessageData` so a future
38
38
  * adapter between the two is a narrow mapping, not a rewrite.
39
39
  */
40
+ import { type AssistantClientToolCall, type AssistantClientToolDeclaration, type AssistantClientToolResult, type AssistantTurnEvent } from '../../../assistant-turn-events.js';
40
41
  export interface AssistantThreadSummary {
41
42
  id: string;
42
43
  title: string;
@@ -72,7 +73,21 @@ export interface ModelOption {
72
73
  id: string;
73
74
  label: string;
74
75
  }
75
- export interface AssistantSendMessageInput {
76
+ /** One streamed turn event, with persisted messages already mapped to the
77
+ * dock's {@link AssistantMessage} shape by the transport (#2908). */
78
+ export type AssistantTransportEvent = AssistantTurnEvent<AssistantMessage>;
79
+ /** Streaming inputs shared by a send and a resumed turn (#2908). A transport
80
+ * that does not stream ignores all three and resolves as before. */
81
+ export interface AssistantTurnStreamInput {
82
+ /** The page's browser tools to offer the model this turn. The server
83
+ * validates and allow-lists them; it never runs them. */
84
+ clientTools?: AssistantClientToolDeclaration[];
85
+ /** Live turn events (status, steps, token preview, persisted messages). */
86
+ onEvent?: (event: AssistantTransportEvent) => void;
87
+ /** Aborts the turn (the dock's Stop). */
88
+ signal?: AbortSignal;
89
+ }
90
+ export interface AssistantSendMessageInput extends AssistantTurnStreamInput {
76
91
  threadId: string;
77
92
  content: string;
78
93
  attachments?: AssistantAttachmentRef[];
@@ -82,6 +97,17 @@ export interface AssistantSendMessageInput {
82
97
  /** The model selected via ModelPicker, when the transport supports one. */
83
98
  model?: string;
84
99
  }
100
+ /** Resume a turn the server suspended on browser tool calls (#2908). */
101
+ export interface AssistantResumeTurnInput extends AssistantTurnStreamInput {
102
+ threadId: string;
103
+ /** The send this turn belongs to. */
104
+ clientRequestId: string;
105
+ /** From the suspension (`clientToolCalls.continuationId`). */
106
+ continuationId: string;
107
+ /** One result per suspended call. */
108
+ results: AssistantClientToolResult[];
109
+ model?: string;
110
+ }
85
111
  export interface AssistantSendMessageResult {
86
112
  /** True when the assistant turn has not resolved yet and the caller should
87
113
  * poll `loadMessages` for the reply (mirrors anytown's `payload.inProgress`,
@@ -89,6 +115,15 @@ export interface AssistantSendMessageResult {
89
115
  inProgress: boolean;
90
116
  userMessage?: AssistantMessage;
91
117
  assistantMessage?: AssistantMessage;
118
+ /** Every message the turn persisted (tool results, the reply), in order,
119
+ * for a streaming transport. */
120
+ messages?: AssistantMessage[];
121
+ /** Set when the turn is waiting on browser tools (#2908). The dock runs
122
+ * them and calls `resumeTurn`. */
123
+ clientToolCalls?: {
124
+ continuationId: string;
125
+ calls: AssistantClientToolCall[];
126
+ };
92
127
  }
93
128
  export interface AssistantTransport {
94
129
  listThreads(): Promise<AssistantThreadSummary[]>;
@@ -101,6 +136,9 @@ export interface AssistantTransport {
101
136
  * transport that has no model choice (e.g. a single fixed backend model)
102
137
  * simply omits this method. */
103
138
  listModels?(): Promise<ModelOption[]>;
139
+ /** Resume a turn suspended on browser tool calls (#2908). Required for a
140
+ * transport that ever returns `clientToolCalls`. */
141
+ resumeTurn?(input: AssistantResumeTurnInput): Promise<AssistantSendMessageResult>;
104
142
  }
105
143
  export interface InMemoryAssistantTransportOptions {
106
144
  /** Simulates a still-processing turn: the Nth send for a given thread
@@ -219,6 +257,9 @@ export interface SmrtAssistantTransportOptions {
219
257
  createThread: (title: string) => Promise<AssistantThreadSummary>;
220
258
  sendMessage: (input: AssistantSendMessageInput) => Promise<AssistantSendMessageResult>;
221
259
  uploadAttachment: (file: File) => Promise<AssistantAttachmentRef>;
260
+ /** Resumes a turn suspended on browser tools (#2908); see
261
+ * `AssistantTransport.resumeTurn`. */
262
+ resumeTurn?: (input: AssistantResumeTurnInput) => Promise<AssistantSendMessageResult>;
222
263
  };
223
264
  /** Static model catalog; when supplied, `listModels()` resolves to it and
224
265
  * `AssistantDock` renders `ModelPicker`. The `model` field of a `send` is
@@ -236,4 +277,16 @@ export interface SmrtAssistantTransportOptions {
236
277
  * `../../../models/ChatThread.ts:16`, `../../../models/ChatMessage.ts:26`).
237
278
  */
238
279
  export declare function createSmrtAssistantTransport(options: SmrtAssistantTransportOptions): AssistantTransport;
280
+ /**
281
+ * Read a streamed assistant turn response (#2908) into an
282
+ * {@link AssistantSendMessageResult}, forwarding each event (with persisted
283
+ * messages mapped by `mapMessage`) to `onEvent`. For a host transport whose
284
+ * send route answers `text/event-stream` (the server side is
285
+ * `runAssistantTurn` + `createAssistantTurnResponse`). Rejects on an in-band
286
+ * `error` or a cut stream.
287
+ */
288
+ export declare function readAssistantTurnResult<W = Record<string, unknown>>(response: Response, options: {
289
+ mapMessage: (wire: W) => AssistantMessage;
290
+ onEvent?: (event: AssistantTransportEvent) => void;
291
+ }): Promise<AssistantSendMessageResult>;
239
292
  //# sourceMappingURL=assistant-transport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"assistant-transport.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/assistant/assistant-transport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"assistant-transport.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/assistant/assistant-transport.ts"],"names":[],"mappings":"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"}