@volter-ai-dev/supercode-ui 0.1.22 → 0.1.24
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.
- package/README.md +9 -0
- package/components.d.ts +2 -0
- package/components.mjs +260 -109
- package/composer.mjs +19 -17
- package/controller.d.ts +20 -0
- package/controller.mjs +69 -12
- package/conversation.d.ts +2 -0
- package/conversation.mjs +192 -44
- package/core.mjs +3 -0
- package/embed.mjs +258 -109
- package/index.d.ts +8 -0
- package/messenger.mjs +258 -109
- package/package.json +1 -1
- package/sessions.mjs +15 -13
- package/styles.css +2 -1
package/composer.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/composer.jsx
|
|
2
|
-
import { useEffect, useRef, useState } from "preact/hooks";
|
|
2
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "preact/hooks";
|
|
3
3
|
|
|
4
4
|
// core.mjs
|
|
5
5
|
var HARNESS_NAMES = Object.freeze({
|
|
@@ -129,10 +129,12 @@ function UiIcon({ name, size = 16, class: className = "" }) {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
// src/context.jsx
|
|
132
|
-
import {
|
|
132
|
+
import { useEffect, useRef, useState } from "preact/hooks";
|
|
133
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
133
134
|
var MAX_CONTEXT_ITEMS = 32;
|
|
134
135
|
var MAX_IMAGE_ITEMS = 4;
|
|
135
136
|
var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
137
|
+
var MAX_RESOLVED_IMAGE_BYTES = 16 * 1024 * 1024;
|
|
136
138
|
var IMAGE_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
|
|
137
139
|
function normalizeContext(value) {
|
|
138
140
|
return (Array.isArray(value) ? value : value ? [value] : []).flatMap((item) => {
|
|
@@ -268,18 +270,18 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
268
270
|
}
|
|
269
271
|
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, onPending, onDraftRestored }) {
|
|
270
272
|
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, context: [], images: [], queue: [] };
|
|
271
|
-
const [draft, setDraft] =
|
|
272
|
-
const [context, setContext] =
|
|
273
|
-
const [images, setImages] =
|
|
274
|
-
const [queue, setQueue] =
|
|
275
|
-
const [dispatching, setDispatching] =
|
|
276
|
-
const [picking, setPicking] =
|
|
277
|
-
const [dragging, setDragging] =
|
|
278
|
-
const [pickerError, setPickerError] =
|
|
279
|
-
const textarea =
|
|
273
|
+
const [draft, setDraft] = useState2(remembered.draft);
|
|
274
|
+
const [context, setContext] = useState2(remembered.context ?? []);
|
|
275
|
+
const [images, setImages] = useState2(remembered.images ?? []);
|
|
276
|
+
const [queue, setQueue] = useState2((remembered.queue ?? []).map((item) => ({ ...item, context: item.context ?? [], images: item.images ?? [] })));
|
|
277
|
+
const [dispatching, setDispatching] = useState2(false);
|
|
278
|
+
const [picking, setPicking] = useState2(false);
|
|
279
|
+
const [dragging, setDragging] = useState2(false);
|
|
280
|
+
const [pickerError, setPickerError] = useState2(null);
|
|
281
|
+
const textarea = useRef2(null);
|
|
280
282
|
useAutosizeTextarea(textarea, draft);
|
|
281
283
|
const remember = (nextDraft, nextContext, nextImages, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, context: nextContext, images: nextImages, queue: nextQueue });
|
|
282
|
-
|
|
284
|
+
useEffect2(() => {
|
|
283
285
|
remember(draft, context, images, queue);
|
|
284
286
|
}, [draft, context, images, memoryKey, queue]);
|
|
285
287
|
const updateQueue = (update) => setQueue((items) => {
|
|
@@ -289,7 +291,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
289
291
|
});
|
|
290
292
|
const queueBlocked = state.busy || pendingStatus !== null || dispatching;
|
|
291
293
|
const queuesNewMessage = state.busy || pendingStatus === "sending" || pendingStatus === "failed" || dispatching;
|
|
292
|
-
|
|
294
|
+
useEffect2(() => {
|
|
293
295
|
if (!queueBlocked && state.canSend && queue.length) {
|
|
294
296
|
const [next, ...rest] = queue;
|
|
295
297
|
setDispatching(true);
|
|
@@ -299,13 +301,13 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
299
301
|
adapter.onIntent({ action: "send", text: next.text, ...next.context.length ? { context: next.context } : {}, ...next.images.length ? { images: next.images } : {} });
|
|
300
302
|
}
|
|
301
303
|
}, [adapter, draft, memoryKey, onPending, queue, queueBlocked, state.canSend]);
|
|
302
|
-
|
|
304
|
+
useEffect2(() => {
|
|
303
305
|
if (pendingStatus !== null || state.busy) setDispatching(false);
|
|
304
306
|
}, [pendingStatus, state.busy]);
|
|
305
|
-
|
|
307
|
+
useEffect2(() => {
|
|
306
308
|
textarea.current?.focus({ preventScroll: true });
|
|
307
309
|
}, [memoryKey]);
|
|
308
|
-
|
|
310
|
+
useEffect2(() => {
|
|
309
311
|
if (!restoreDraft) return;
|
|
310
312
|
setDraft(restoreDraft.text);
|
|
311
313
|
const restoredContext = normalizeContext(restoreDraft.context);
|
|
@@ -316,7 +318,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
316
318
|
textarea.current?.focus({ preventScroll: true });
|
|
317
319
|
onDraftRestored?.(restoreDraft.id);
|
|
318
320
|
}, [onDraftRestored, restoreDraft?.id]);
|
|
319
|
-
|
|
321
|
+
useEffect2(() => {
|
|
320
322
|
const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
|
|
321
323
|
return () => clearTimeout(timer);
|
|
322
324
|
}, [adapter, draft]);
|
package/controller.d.ts
CHANGED
|
@@ -52,6 +52,25 @@ export function projectClientSnapshot(
|
|
|
52
52
|
options?: ClientProjectionOptions,
|
|
53
53
|
): SupercodeUiState;
|
|
54
54
|
|
|
55
|
+
export interface ResolvableTranscriptImage {
|
|
56
|
+
id?: string;
|
|
57
|
+
label: string;
|
|
58
|
+
url: string;
|
|
59
|
+
mediaType?: string;
|
|
60
|
+
byteSize?: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ClientProjection {
|
|
64
|
+
state: SupercodeUiState;
|
|
65
|
+
/** Returns only an image admitted to this projection's bounded transcript window. */
|
|
66
|
+
resolveImage(reference: string): ResolvableTranscriptImage | null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function createClientProjection(
|
|
70
|
+
snapshot: SupercodeClientSnapshot,
|
|
71
|
+
options?: ClientProjectionOptions,
|
|
72
|
+
): ClientProjection;
|
|
73
|
+
|
|
55
74
|
export interface ControllerBindingOptions {
|
|
56
75
|
projection?: () => ClientProjectionOptions;
|
|
57
76
|
onIntent?: (intent: SupercodeUiIntent) => void | Promise<void>;
|
|
@@ -63,6 +82,7 @@ export interface ControllerBindingOptions {
|
|
|
63
82
|
onLoadSessions?: () => void | Promise<void>;
|
|
64
83
|
onLoadEarlier?: () => void | Promise<void>;
|
|
65
84
|
copyText?: UiAdapter['copyText'];
|
|
85
|
+
resolveImage?: UiAdapter['resolveImage'];
|
|
66
86
|
}
|
|
67
87
|
|
|
68
88
|
export interface SupercodeUiBinding {
|
package/controller.mjs
CHANGED
|
@@ -99,18 +99,53 @@ function projectContext(context) {
|
|
|
99
99
|
return projected.length ? projected : undefined;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
function
|
|
102
|
+
function imageMetadata(url) {
|
|
103
|
+
if (!url.startsWith('data:image/')) return {};
|
|
104
|
+
const header = url.slice(5, 256);
|
|
105
|
+
const comma = header.indexOf(',');
|
|
106
|
+
if (comma < 0) return {};
|
|
107
|
+
const declaration = header.slice(0, comma);
|
|
108
|
+
const mediaType = declaration.split(';', 1)[0].toLowerCase();
|
|
109
|
+
if (!mediaType.startsWith('image/')) return {};
|
|
110
|
+
if (!declaration.toLowerCase().endsWith(';base64')) return { mediaType };
|
|
111
|
+
const payloadLength = url.length - 5 - comma - 1;
|
|
112
|
+
const padding = url.endsWith('==') ? 2 : url.endsWith('=') ? 1 : 0;
|
|
113
|
+
return { mediaType, byteSize: Math.max(0, Math.floor(payloadLength * 3 / 4) - padding) };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function imageReference(entryId, item, index) {
|
|
117
|
+
// The host treats this only as a key into the projection-scoped registry below. Keeping the key
|
|
118
|
+
// deterministic prevents a streamed transcript refresh from restarting an image already open in
|
|
119
|
+
// the viewer, while the registry still rejects references outside the admitted render window.
|
|
120
|
+
return JSON.stringify([entryId, typeof item.id === 'string' ? item.id : null, index]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function projectImages(images, entryId, imageRegistry) {
|
|
103
124
|
if (!Array.isArray(images)) return undefined;
|
|
104
|
-
const projected = images.flatMap((item) => {
|
|
125
|
+
const projected = images.flatMap((item, index) => {
|
|
105
126
|
if (!item || typeof item !== 'object' || typeof item.label !== 'string') return [];
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
127
|
+
const sourceUrl = typeof item.url === 'string' ? item.url : null;
|
|
128
|
+
const complete = sourceUrl !== null && !sourceUrl.endsWith('\n…');
|
|
129
|
+
const metadata = complete ? imageMetadata(sourceUrl) : {};
|
|
130
|
+
const url = complete && (!sourceUrl.startsWith('data:image/') || sourceUrl.length <= 256_000)
|
|
131
|
+
? sourceUrl
|
|
109
132
|
: null;
|
|
133
|
+
let reference = null;
|
|
134
|
+
if (complete && sourceUrl.startsWith('data:image/') && !url && imageRegistry && Number.isSafeInteger(metadata.byteSize)) {
|
|
135
|
+
reference = imageReference(entryId, item, index);
|
|
136
|
+
imageRegistry.set(reference, {
|
|
137
|
+
...(typeof item.id === 'string' ? { id: item.id } : {}),
|
|
138
|
+
label: item.label,
|
|
139
|
+
url: sourceUrl,
|
|
140
|
+
...metadata,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
110
143
|
return [{
|
|
111
144
|
...(typeof item.id === 'string' ? { id: item.id } : {}),
|
|
112
145
|
label: item.label,
|
|
146
|
+
...metadata,
|
|
113
147
|
...(url ? { url } : {}),
|
|
148
|
+
...(reference ? { reference } : {}),
|
|
114
149
|
}];
|
|
115
150
|
}).slice(0, 4);
|
|
116
151
|
return projected.length ? projected : undefined;
|
|
@@ -124,13 +159,13 @@ function requestSummary(entry) {
|
|
|
124
159
|
return options ? `${entry.requestKind}: ${options}${resolution}` : `${entry.requestKind ?? 'request'}${resolution}`;
|
|
125
160
|
}
|
|
126
161
|
|
|
127
|
-
function projectConversationEntry(entry, maxEntryChars) {
|
|
162
|
+
function projectConversationEntry(entry, maxEntryChars, imageRegistry) {
|
|
128
163
|
if (!entry || typeof entry !== 'object' || typeof entry.id !== 'string') return null;
|
|
129
164
|
if (entry.kind === 'message') {
|
|
130
165
|
if (entry.visibility === 'context') return null;
|
|
131
166
|
const body = truncate(entry.text, maxEntryChars);
|
|
132
167
|
const context = projectContext(entry.context);
|
|
133
|
-
const images = projectImages(entry.images);
|
|
168
|
+
const images = projectImages(entry.images, entry.id, imageRegistry);
|
|
134
169
|
return {
|
|
135
170
|
id: entry.id,
|
|
136
171
|
role: entry.role,
|
|
@@ -201,7 +236,7 @@ function projectConversationEntry(entry, maxEntryChars) {
|
|
|
201
236
|
return null;
|
|
202
237
|
}
|
|
203
238
|
|
|
204
|
-
function projectConversation(conversation, options) {
|
|
239
|
+
function projectConversation(conversation, options, imageRegistry) {
|
|
205
240
|
if (!Array.isArray(conversation)) return [];
|
|
206
241
|
const maxEntries = positiveInteger(options.maxEntries, DEFAULT_MAX_ENTRIES);
|
|
207
242
|
const maxEntryChars = positiveInteger(options.maxEntryChars, DEFAULT_MAX_ENTRY_CHARS);
|
|
@@ -215,7 +250,7 @@ function projectConversation(conversation, options) {
|
|
|
215
250
|
for (;
|
|
216
251
|
index >= 0 && rows.length < maxEntries && scanned < maxScanEntries;
|
|
217
252
|
index -= 1, scanned += 1) {
|
|
218
|
-
const row = projectConversationEntry(conversation[index], maxEntryChars);
|
|
253
|
+
const row = projectConversationEntry(conversation[index], maxEntryChars, imageRegistry);
|
|
219
254
|
if (row) rows.push(row);
|
|
220
255
|
}
|
|
221
256
|
|
|
@@ -229,7 +264,7 @@ function projectConversation(conversation, options) {
|
|
|
229
264
|
rows.length = oldestVisibleUser + 1;
|
|
230
265
|
} else {
|
|
231
266
|
for (; index >= 0 && scanned < maxScanEntries; index -= 1, scanned += 1) {
|
|
232
|
-
const row = projectConversationEntry(conversation[index], maxEntryChars);
|
|
267
|
+
const row = projectConversationEntry(conversation[index], maxEntryChars, imageRegistry);
|
|
233
268
|
if (row?.role !== 'user') continue;
|
|
234
269
|
if (rows.length === maxEntries) rows[rows.length - 1] = row;
|
|
235
270
|
else rows.push(row);
|
|
@@ -300,7 +335,7 @@ function projectPill(snapshot) {
|
|
|
300
335
|
return { tone: 'live', label: text(`${label(harness)} ready`) };
|
|
301
336
|
}
|
|
302
337
|
|
|
303
|
-
|
|
338
|
+
function projectClientSnapshotInternal(snapshot, options, imageRegistry) {
|
|
304
339
|
const now = Number.isFinite(options.now) ? options.now : Date.now();
|
|
305
340
|
const busy = ['running', 'interrupting', 'reconciling'].includes(snapshot.turn?.state);
|
|
306
341
|
const actions = snapshot.availableActions ?? {};
|
|
@@ -325,7 +360,7 @@ export function projectClientSnapshot(snapshot, options = {}) {
|
|
|
325
360
|
? snapshot.connection?.ownsRuntime ? active : null
|
|
326
361
|
: options.owned;
|
|
327
362
|
const maxEntries = positiveInteger(options.maxEntries, DEFAULT_MAX_ENTRIES);
|
|
328
|
-
const transcript = projectConversation(snapshot.conversation ?? [], options);
|
|
363
|
+
const transcript = projectConversation(snapshot.conversation ?? [], options, imageRegistry);
|
|
329
364
|
const startup = snapshot.availability === 'loading'
|
|
330
365
|
? snapshot.operation === 'start' ? 'starting' : snapshot.operation === 'refresh' ? 'discovering' : 'connecting'
|
|
331
366
|
: 'ready';
|
|
@@ -390,6 +425,27 @@ export function projectClientSnapshot(snapshot, options = {}) {
|
|
|
390
425
|
});
|
|
391
426
|
}
|
|
392
427
|
|
|
428
|
+
export function projectClientSnapshot(snapshot, options = {}) {
|
|
429
|
+
return projectClientSnapshotInternal(snapshot, options, null);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Project a bounded UI state together with a host-only resolver for data images omitted from that
|
|
434
|
+
* state. The resolver knows only the images admitted by this exact projection, so a browser can
|
|
435
|
+
* neither force a whole-history scan nor use a guessed reference to read an unrelated session.
|
|
436
|
+
*/
|
|
437
|
+
export function createClientProjection(snapshot, options = {}) {
|
|
438
|
+
const images = new Map();
|
|
439
|
+
const state = projectClientSnapshotInternal(snapshot, options, images);
|
|
440
|
+
return {
|
|
441
|
+
state,
|
|
442
|
+
resolveImage(reference) {
|
|
443
|
+
const image = typeof reference === 'string' ? images.get(reference) : null;
|
|
444
|
+
return image ? { ...image } : null;
|
|
445
|
+
},
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
393
449
|
async function dispatchStandard(controller, intent, options) {
|
|
394
450
|
const snapshot = controller.getSnapshot();
|
|
395
451
|
const active = snapshot.activeSessionKey;
|
|
@@ -433,6 +489,7 @@ export function createControllerBinding(controller, options = {}) {
|
|
|
433
489
|
.then(() => undefined);
|
|
434
490
|
},
|
|
435
491
|
...(options.copyText ? { copyText: options.copyText } : {}),
|
|
492
|
+
...(options.resolveImage ? { resolveImage: options.resolveImage } : {}),
|
|
436
493
|
};
|
|
437
494
|
return {
|
|
438
495
|
adapter,
|
package/conversation.d.ts
CHANGED
package/conversation.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/conversation.jsx
|
|
2
|
-
import { Fragment as
|
|
3
|
-
import { useEffect as
|
|
2
|
+
import { Fragment as Fragment3 } from "preact";
|
|
3
|
+
import { useEffect as useEffect3, useId, useLayoutEffect, useRef as useRef3, useState as useState2 } from "preact/hooks";
|
|
4
4
|
|
|
5
5
|
// core.mjs
|
|
6
6
|
var HARNESS_NAMES = Object.freeze({
|
|
@@ -622,18 +622,164 @@ function UiIcon({ name, size = 16, class: className = "" }) {
|
|
|
622
622
|
}
|
|
623
623
|
|
|
624
624
|
// src/context.jsx
|
|
625
|
-
import {
|
|
625
|
+
import { useEffect as useEffect2, useRef as useRef2, useState } from "preact/hooks";
|
|
626
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
626
627
|
var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
627
|
-
|
|
628
|
+
var MAX_RESOLVED_IMAGE_BYTES = 16 * 1024 * 1024;
|
|
629
|
+
function imageFilename(label) {
|
|
630
|
+
const value = label.trim().replace(/[\\/:*?"<>|]+/g, "-");
|
|
631
|
+
return value || "image";
|
|
632
|
+
}
|
|
633
|
+
function ImageViewer({ items, index, adapter, onChange, onClose }) {
|
|
634
|
+
const dialog = useRef2(null);
|
|
635
|
+
const reset = useRef2(null);
|
|
636
|
+
const resolutions = useRef2(/* @__PURE__ */ new Map());
|
|
637
|
+
const alive = useRef2(true);
|
|
638
|
+
const [, redraw] = useState(0);
|
|
639
|
+
const [copyState, setCopyState2] = useState("idle");
|
|
640
|
+
const item = items[index];
|
|
641
|
+
const key = item?.reference ?? item?.url ?? `${item?.id ?? ""}:${index}`;
|
|
642
|
+
const resolution = item?.url ? null : resolutions.current.get(key);
|
|
643
|
+
const imageUrl = item?.url ?? (resolution?.status === "ready" ? resolution.url : null);
|
|
644
|
+
const remote = imageUrl?.startsWith("http://") || imageUrl?.startsWith("https://");
|
|
645
|
+
const resolve = (candidate, force = false) => {
|
|
646
|
+
if (candidate?.url || !candidate?.reference || !adapter?.resolveImage) return;
|
|
647
|
+
const candidateKey = candidate.reference;
|
|
648
|
+
const current = resolutions.current.get(candidateKey);
|
|
649
|
+
if (!force && (current?.status === "loading" || current?.status === "ready")) return;
|
|
650
|
+
if (current?.url) URL.revokeObjectURL(current.url);
|
|
651
|
+
resolutions.current.set(candidateKey, { status: "loading" });
|
|
652
|
+
redraw((value) => value + 1);
|
|
653
|
+
Promise.resolve().then(() => adapter.resolveImage(candidate)).then((blob) => {
|
|
654
|
+
if (!(blob instanceof Blob) || !blob.type.startsWith("image/")) throw new Error("The host returned an invalid image.");
|
|
655
|
+
if (blob.size > MAX_RESOLVED_IMAGE_BYTES) throw new Error("This image is too large to preview safely.");
|
|
656
|
+
if (!alive.current) return;
|
|
657
|
+
const url = URL.createObjectURL(blob);
|
|
658
|
+
resolutions.current.set(candidateKey, { status: "ready", url });
|
|
659
|
+
redraw((value) => value + 1);
|
|
660
|
+
}).catch((error) => {
|
|
661
|
+
if (!alive.current) return;
|
|
662
|
+
resolutions.current.set(candidateKey, {
|
|
663
|
+
status: "error",
|
|
664
|
+
message: error instanceof Error && error.message ? error.message : "Could not load this image."
|
|
665
|
+
});
|
|
666
|
+
redraw((value) => value + 1);
|
|
667
|
+
});
|
|
668
|
+
};
|
|
669
|
+
useEffect2(() => {
|
|
670
|
+
alive.current = true;
|
|
671
|
+
if (!dialog.current?.open) dialog.current?.showModal();
|
|
672
|
+
return () => {
|
|
673
|
+
alive.current = false;
|
|
674
|
+
clearTimeout(reset.current);
|
|
675
|
+
for (const value of resolutions.current.values()) if (value.url) URL.revokeObjectURL(value.url);
|
|
676
|
+
resolutions.current.clear();
|
|
677
|
+
};
|
|
678
|
+
}, []);
|
|
679
|
+
useEffect2(() => {
|
|
680
|
+
clearTimeout(reset.current);
|
|
681
|
+
setCopyState2("idle");
|
|
682
|
+
resolve(item);
|
|
683
|
+
}, [index, item?.reference]);
|
|
684
|
+
if (!item || !item.url && (!item.reference || !adapter?.resolveImage)) return null;
|
|
685
|
+
const move = (amount) => onChange((index + amount + items.length) % items.length);
|
|
686
|
+
const copy = async () => {
|
|
687
|
+
try {
|
|
688
|
+
await adapter.copyText(imageUrl);
|
|
689
|
+
setCopyState2("copied");
|
|
690
|
+
} catch {
|
|
691
|
+
setCopyState2("failed");
|
|
692
|
+
}
|
|
693
|
+
clearTimeout(reset.current);
|
|
694
|
+
reset.current = setTimeout(() => setCopyState2("idle"), 1500);
|
|
695
|
+
};
|
|
696
|
+
const close = () => dialog.current?.close();
|
|
697
|
+
return /* @__PURE__ */ jsxs2(
|
|
698
|
+
"dialog",
|
|
699
|
+
{
|
|
700
|
+
ref: dialog,
|
|
701
|
+
class: "scui-image-viewer",
|
|
702
|
+
"aria-label": `Image preview: ${item.label}`,
|
|
703
|
+
onClose,
|
|
704
|
+
onClick: (event) => {
|
|
705
|
+
if (event.target === event.currentTarget) close();
|
|
706
|
+
},
|
|
707
|
+
onKeyDown: (event) => {
|
|
708
|
+
if (items.length < 2 || !["ArrowLeft", "ArrowRight"].includes(event.key)) return;
|
|
709
|
+
event.preventDefault();
|
|
710
|
+
move(event.key === "ArrowLeft" ? -1 : 1);
|
|
711
|
+
},
|
|
712
|
+
children: [
|
|
713
|
+
/* @__PURE__ */ jsxs2("header", { children: [
|
|
714
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
715
|
+
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
716
|
+
items.length > 1 ? /* @__PURE__ */ jsxs2("small", { children: [
|
|
717
|
+
index + 1,
|
|
718
|
+
" of ",
|
|
719
|
+
items.length
|
|
720
|
+
] }) : null
|
|
721
|
+
] }),
|
|
722
|
+
/* @__PURE__ */ jsxs2("nav", { "aria-label": "Image actions", children: [
|
|
723
|
+
remote && adapter?.copyText ? /* @__PURE__ */ jsx3("button", { type: "button", "aria-label": copyState === "copied" ? "Image link copied" : copyState === "failed" ? "Could not copy image link" : "Copy image link", title: "Copy image link", "data-status": copyState, onClick: copy, children: /* @__PURE__ */ jsx3(UiIcon, { name: copyState === "copied" ? "check" : "copy", size: 16 }) }) : null,
|
|
724
|
+
imageUrl ? remote ? /* @__PURE__ */ jsx3("a", { href: imageUrl, target: "_blank", rel: "noreferrer", "aria-label": "Open original image", title: "Open original image", children: /* @__PURE__ */ jsx3(UiIcon, { name: "image", size: 16 }) }) : /* @__PURE__ */ jsx3("a", { href: imageUrl, download: imageFilename(item.label), "aria-label": "Download image", title: "Download image", children: /* @__PURE__ */ jsx3(UiIcon, { name: "down", size: 16 }) }) : null,
|
|
725
|
+
/* @__PURE__ */ jsx3("button", { type: "button", "aria-label": "Close image preview", title: "Close", onClick: close, children: /* @__PURE__ */ jsx3(UiIcon, { name: "close", size: 17 }) })
|
|
726
|
+
] })
|
|
727
|
+
] }),
|
|
728
|
+
/* @__PURE__ */ jsxs2("figure", { children: [
|
|
729
|
+
imageUrl ? /* @__PURE__ */ jsx3("img", { src: imageUrl, alt: item.label }) : resolution?.status === "error" ? /* @__PURE__ */ jsxs2("div", { class: "scui-image-resolution", role: "alert", children: [
|
|
730
|
+
/* @__PURE__ */ jsx3(UiIcon, { name: "image", size: 28 }),
|
|
731
|
+
/* @__PURE__ */ jsx3("strong", { children: "Could not load image" }),
|
|
732
|
+
/* @__PURE__ */ jsx3("small", { children: resolution.message }),
|
|
733
|
+
/* @__PURE__ */ jsx3("button", { type: "button", onClick: () => resolve(item, true), children: "Retry" })
|
|
734
|
+
] }) : /* @__PURE__ */ jsxs2("div", { class: "scui-image-resolution", role: "status", children: [
|
|
735
|
+
/* @__PURE__ */ jsx3("i", { class: "scui-control-spinner" }),
|
|
736
|
+
/* @__PURE__ */ jsx3("strong", { children: "Loading image\u2026" }),
|
|
737
|
+
/* @__PURE__ */ jsx3("small", { children: "The original stays out of the transcript payload." })
|
|
738
|
+
] }),
|
|
739
|
+
items.length > 1 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
740
|
+
/* @__PURE__ */ jsx3("button", { type: "button", class: "scui-image-previous", "aria-label": "Previous image", onClick: () => move(-1), children: /* @__PURE__ */ jsx3(UiIcon, { name: "chevron", size: 19 }) }),
|
|
741
|
+
/* @__PURE__ */ jsx3("button", { type: "button", class: "scui-image-next", "aria-label": "Next image", onClick: () => move(1), children: /* @__PURE__ */ jsx3(UiIcon, { name: "chevron", size: 19 }) })
|
|
742
|
+
] }) : null
|
|
743
|
+
] })
|
|
744
|
+
]
|
|
745
|
+
}
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
function MessageImages({ items, adapter }) {
|
|
749
|
+
const [active, setActive] = useState(null);
|
|
750
|
+
const opener = useRef2(null);
|
|
628
751
|
if (!items?.length) return null;
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
752
|
+
const viewable = items.filter((item) => item.url || item.reference && adapter?.resolveImage);
|
|
753
|
+
const close = () => {
|
|
754
|
+
setActive(null);
|
|
755
|
+
requestAnimationFrame(() => opener.current?.focus({ preventScroll: true }));
|
|
756
|
+
};
|
|
757
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
758
|
+
/* @__PURE__ */ jsx3("div", { class: "scui-message-images", "aria-label": "Message images", children: items.map((item, index) => item.url ? /* @__PURE__ */ jsx3("button", { type: "button", "aria-label": `View image ${item.label}`, onClick: (event) => {
|
|
759
|
+
opener.current = event.currentTarget;
|
|
760
|
+
setActive(viewable.indexOf(item));
|
|
761
|
+
}, children: /* @__PURE__ */ jsx3("img", { src: item.url, alt: "" }) }, item.id ?? `${item.label}:${index}`) : item.reference && adapter?.resolveImage ? /* @__PURE__ */ jsxs2("button", { type: "button", "data-lazy": "true", "aria-label": `Load image ${item.label}`, onClick: (event) => {
|
|
762
|
+
opener.current = event.currentTarget;
|
|
763
|
+
setActive(viewable.indexOf(item));
|
|
764
|
+
}, children: [
|
|
765
|
+
/* @__PURE__ */ jsx3(UiIcon, { name: "image", size: 16 }),
|
|
766
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
767
|
+
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
768
|
+
/* @__PURE__ */ jsx3("small", { children: "Load preview" })
|
|
769
|
+
] })
|
|
770
|
+
] }, item.id ?? `${item.label}:${index}`) : /* @__PURE__ */ jsxs2("span", { "data-unavailable": "true", children: [
|
|
771
|
+
/* @__PURE__ */ jsx3(UiIcon, { name: "image", size: 14 }),
|
|
772
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
773
|
+
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
774
|
+
/* @__PURE__ */ jsx3("small", { children: "Preview unavailable" })
|
|
775
|
+
] })
|
|
776
|
+
] }, item.id ?? `${item.label}:${index}`)) }),
|
|
777
|
+
active !== null && viewable[active] ? /* @__PURE__ */ jsx3(ImageViewer, { items: viewable, index: active, adapter, onChange: setActive, onClose: close }) : null
|
|
778
|
+
] });
|
|
633
779
|
}
|
|
634
780
|
|
|
635
781
|
// src/conversation.jsx
|
|
636
|
-
import { Fragment as
|
|
782
|
+
import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
637
783
|
function LoadingStatus({ state, compact = false }) {
|
|
638
784
|
const copy = {
|
|
639
785
|
connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
|
|
@@ -682,9 +828,9 @@ function ContextDisclosure({ context }) {
|
|
|
682
828
|
] });
|
|
683
829
|
}
|
|
684
830
|
function MessageMeta({ entry, adapter }) {
|
|
685
|
-
const [copyState, setCopyState2] =
|
|
686
|
-
const reset =
|
|
687
|
-
|
|
831
|
+
const [copyState, setCopyState2] = useState2("idle");
|
|
832
|
+
const reset = useRef3(null);
|
|
833
|
+
useEffect3(() => () => clearTimeout(reset.current), []);
|
|
688
834
|
const date = entry.ts === null ? null : new Date(entry.ts);
|
|
689
835
|
const validDate = date && Number.isFinite(date.valueOf()) ? date : null;
|
|
690
836
|
if (!validDate && (!adapter?.copyText || !entry.text)) return null;
|
|
@@ -705,33 +851,33 @@ function MessageMeta({ entry, adapter }) {
|
|
|
705
851
|
] });
|
|
706
852
|
}
|
|
707
853
|
var TOOL_ICONS = {
|
|
708
|
-
read: () => /* @__PURE__ */ jsxs3(
|
|
854
|
+
read: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
709
855
|
/* @__PURE__ */ jsx4("path", { d: "M5 2.75h7.25L15 5.5v7.75A1.75 1.75 0 0 1 13.25 15h-8.5A1.75 1.75 0 0 1 3 13.25v-8.5A2 2 0 0 1 5 2.75Z" }),
|
|
710
856
|
/* @__PURE__ */ jsx4("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
|
|
711
857
|
] }),
|
|
712
|
-
search: () => /* @__PURE__ */ jsxs3(
|
|
858
|
+
search: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
713
859
|
/* @__PURE__ */ jsx4("circle", { cx: "8", cy: "8", r: "4.5" }),
|
|
714
860
|
/* @__PURE__ */ jsx4("path", { d: "m11.5 11.5 3 3" })
|
|
715
861
|
] }),
|
|
716
|
-
edit: () => /* @__PURE__ */ jsxs3(
|
|
862
|
+
edit: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
717
863
|
/* @__PURE__ */ jsx4("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
|
|
718
864
|
/* @__PURE__ */ jsx4("path", { d: "m10 5 3 3" })
|
|
719
865
|
] }),
|
|
720
|
-
command: () => /* @__PURE__ */ jsx4(
|
|
721
|
-
test: () => /* @__PURE__ */ jsxs3(
|
|
866
|
+
command: () => /* @__PURE__ */ jsx4(Fragment4, { children: /* @__PURE__ */ jsx4("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
|
|
867
|
+
test: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
722
868
|
/* @__PURE__ */ jsx4("path", { d: "M6 2.5v3L3 12a2 2 0 0 0 1.8 3h8.4a2 2 0 0 0 1.8-3l-3-6.5v-3M5 9h8" }),
|
|
723
869
|
/* @__PURE__ */ jsx4("path", { d: "M5 2.5h8" })
|
|
724
870
|
] }),
|
|
725
|
-
web: () => /* @__PURE__ */ jsxs3(
|
|
871
|
+
web: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
726
872
|
/* @__PURE__ */ jsx4("circle", { cx: "9", cy: "9", r: "6.5" }),
|
|
727
873
|
/* @__PURE__ */ jsx4("path", { d: "M2.75 9h12.5M9 2.5c2 1.8 3 4 3 6.5s-1 4.7-3 6.5c-2-1.8-3-4-3-6.5s1-4.7 3-6.5Z" })
|
|
728
874
|
] }),
|
|
729
|
-
agent: () => /* @__PURE__ */ jsxs3(
|
|
875
|
+
agent: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
730
876
|
/* @__PURE__ */ jsx4("circle", { cx: "9", cy: "6", r: "2.5" }),
|
|
731
877
|
/* @__PURE__ */ jsx4("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
|
|
732
878
|
] }),
|
|
733
|
-
plan: () => /* @__PURE__ */ jsx4(
|
|
734
|
-
other: () => /* @__PURE__ */ jsxs3(
|
|
879
|
+
plan: () => /* @__PURE__ */ jsx4(Fragment4, { children: /* @__PURE__ */ jsx4("path", { d: "m3 5 1 1 2-2M3 9l1 1 2-2M3 13l1 1 2-2M8 5h7M8 9h7M8 13h7" }) }),
|
|
880
|
+
other: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
735
881
|
/* @__PURE__ */ jsx4("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
|
|
736
882
|
/* @__PURE__ */ jsx4("circle", { cx: "9", cy: "9", r: "3.5" })
|
|
737
883
|
] })
|
|
@@ -797,9 +943,9 @@ function ToolMetrics({ presentation }) {
|
|
|
797
943
|
}
|
|
798
944
|
function PendingElapsed({ now }) {
|
|
799
945
|
const clock = now ?? Date.now;
|
|
800
|
-
const started =
|
|
801
|
-
const [elapsed, setElapsed] =
|
|
802
|
-
|
|
946
|
+
const started = useRef3(clock());
|
|
947
|
+
const [elapsed, setElapsed] = useState2(0);
|
|
948
|
+
useEffect3(() => {
|
|
803
949
|
const timer = setInterval(() => setElapsed(Math.max(0, clock() - started.current)), 1e3);
|
|
804
950
|
return () => clearInterval(timer);
|
|
805
951
|
}, [clock]);
|
|
@@ -840,7 +986,7 @@ function SearchPreview({ presentation }) {
|
|
|
840
986
|
] }) : null,
|
|
841
987
|
lines.length ? /* @__PURE__ */ jsx4("ol", { children: lines.map((line, index) => {
|
|
842
988
|
const match = /^(.*?):(\d+)(?::(\d+))?:(.*)$/.exec(line);
|
|
843
|
-
return /* @__PURE__ */ jsx4("li", { children: match ? /* @__PURE__ */ jsxs3(
|
|
989
|
+
return /* @__PURE__ */ jsx4("li", { children: match ? /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
844
990
|
/* @__PURE__ */ jsx4("code", { children: match[1] }),
|
|
845
991
|
/* @__PURE__ */ jsxs3("small", { children: [
|
|
846
992
|
match[2],
|
|
@@ -873,9 +1019,9 @@ function ToolPreview({ presentation, entry }) {
|
|
|
873
1019
|
return presentation.preview ? /* @__PURE__ */ jsx4("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
|
|
874
1020
|
}
|
|
875
1021
|
function ToolActions({ presentation, adapter }) {
|
|
876
|
-
const [copied, setCopied] =
|
|
877
|
-
const reset =
|
|
878
|
-
|
|
1022
|
+
const [copied, setCopied] = useState2(false);
|
|
1023
|
+
const reset = useRef3(null);
|
|
1024
|
+
useEffect3(() => () => clearTimeout(reset.current), []);
|
|
879
1025
|
if (!adapter?.copyText) return null;
|
|
880
1026
|
const action = presentation.command ? ["Copy command", presentation.command] : presentation.path ? ["Copy path", presentation.path] : presentation.url ? ["Copy URL", presentation.url] : presentation.query ? ["Copy query", presentation.query] : null;
|
|
881
1027
|
const copy = async () => {
|
|
@@ -922,7 +1068,7 @@ function TranscriptEntry({ entry, state, adapter }) {
|
|
|
922
1068
|
}
|
|
923
1069
|
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx4("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
|
|
924
1070
|
return /* @__PURE__ */ jsxs3("article", { class: "scui-message", "data-role": entry.role, "aria-label": `${entry.role === "user" ? "Your" : "Assistant"} message`, children: [
|
|
925
|
-
/* @__PURE__ */ jsx4(MessageImages, { items: entry.images }),
|
|
1071
|
+
/* @__PURE__ */ jsx4(MessageImages, { items: entry.images, adapter }),
|
|
926
1072
|
/* @__PURE__ */ jsx4(Markdown, { value: entry.text, copyText: adapter?.copyText }),
|
|
927
1073
|
/* @__PURE__ */ jsx4(ContextDisclosure, { context: entry.context }),
|
|
928
1074
|
entry.truncated ? /* @__PURE__ */ jsx4("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null,
|
|
@@ -931,14 +1077,14 @@ function TranscriptEntry({ entry, state, adapter }) {
|
|
|
931
1077
|
}
|
|
932
1078
|
function ToolRow({ entry, workspace, open = false, adapter }) {
|
|
933
1079
|
const presentation = entry.presentation ?? createToolPresentation(entry);
|
|
934
|
-
const [expanded, setExpanded] =
|
|
935
|
-
|
|
1080
|
+
const [expanded, setExpanded] = useState2(open || entry.status === "pending");
|
|
1081
|
+
useEffect3(() => {
|
|
936
1082
|
if (entry.status === "pending") setExpanded(true);
|
|
937
1083
|
}, [entry.status]);
|
|
938
1084
|
const target = compactToolTarget(presentation.target, workspace);
|
|
939
1085
|
const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
|
|
940
1086
|
const category = presentation.category ?? toolCategory(entry);
|
|
941
|
-
const summary = /* @__PURE__ */ jsxs3(
|
|
1087
|
+
const summary = /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
942
1088
|
/* @__PURE__ */ jsx4(ToolIcon, { category }),
|
|
943
1089
|
/* @__PURE__ */ jsx4("strong", { children: toolAction2(entry, category, presentation) }),
|
|
944
1090
|
target ? /* @__PURE__ */ jsx4("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
|
|
@@ -966,9 +1112,9 @@ function ToolRow({ entry, workspace, open = false, adapter }) {
|
|
|
966
1112
|
function ActivityGroup({ entries, state, adapter }) {
|
|
967
1113
|
if (entries.length === 1) return /* @__PURE__ */ jsx4("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx4(ToolRow, { entry: entries[0], workspace: state.workspace, adapter }) });
|
|
968
1114
|
const active = entries.some((entry) => entry.status === "pending");
|
|
969
|
-
const [open, setOpen] =
|
|
1115
|
+
const [open, setOpen] = useState2(active);
|
|
970
1116
|
const id = useId();
|
|
971
|
-
|
|
1117
|
+
useEffect3(() => {
|
|
972
1118
|
if (active) setOpen(true);
|
|
973
1119
|
}, [active]);
|
|
974
1120
|
return /* @__PURE__ */ jsxs3("section", { class: "scui-activity", children: [
|
|
@@ -1044,9 +1190,9 @@ function SessionDetails({ semantics }) {
|
|
|
1044
1190
|
}
|
|
1045
1191
|
var conversationMemory = /* @__PURE__ */ new Map();
|
|
1046
1192
|
function ConversationAnnouncements({ state }) {
|
|
1047
|
-
const previousBusy =
|
|
1048
|
-
const [announcement, setAnnouncement] =
|
|
1049
|
-
|
|
1193
|
+
const previousBusy = useRef3(state.busy);
|
|
1194
|
+
const [announcement, setAnnouncement] = useState2("");
|
|
1195
|
+
useEffect3(() => {
|
|
1050
1196
|
if (previousBusy.current && !state.busy && !state.error) {
|
|
1051
1197
|
setAnnouncement(`${harnessDisplayName(state.harness) || "Coding agent"} finished working`);
|
|
1052
1198
|
}
|
|
@@ -1055,13 +1201,13 @@ function ConversationAnnouncements({ state }) {
|
|
|
1055
1201
|
return /* @__PURE__ */ jsx4("span", { class: "scui-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement });
|
|
1056
1202
|
}
|
|
1057
1203
|
function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null, unreadAfterMessages = null }) {
|
|
1058
|
-
const scroller =
|
|
1204
|
+
const scroller = useRef3(null);
|
|
1059
1205
|
const remembered = conversationMemory.get(memoryKey) ?? { top: null, atBottom: true };
|
|
1060
|
-
const [atBottom, setAtBottom] =
|
|
1061
|
-
const earlierAnchor =
|
|
1062
|
-
const restored =
|
|
1206
|
+
const [atBottom, setAtBottom] = useState2(remembered.atBottom);
|
|
1207
|
+
const earlierAnchor = useRef3(null);
|
|
1208
|
+
const restored = useRef3(false);
|
|
1063
1209
|
const blocks = groupConversation(state.transcript);
|
|
1064
|
-
const unreadBoundary =
|
|
1210
|
+
const unreadBoundary = useRef3(Number.isSafeInteger(unreadAfterMessages) && unreadAfterMessages >= 0 ? unreadAfterMessages : null);
|
|
1065
1211
|
const unreadBlock = unreadBoundary.current === null ? -1 : blocks.findIndex((block) => {
|
|
1066
1212
|
const entries = block.kind === "activity" ? block.entries : [block.entry];
|
|
1067
1213
|
return entries.some((entry) => Number.isSafeInteger(entry.messageIndex) && entry.messageIndex > unreadBoundary.current);
|
|
@@ -1120,12 +1266,12 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
1120
1266
|
}, children: "Load earlier messages" }) : null,
|
|
1121
1267
|
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx4(LoadingStatus, { state }) : null,
|
|
1122
1268
|
!blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */ jsx4(Empty, { state, adapter, value: null }) : /* @__PURE__ */ jsx4("div", { class: "scui-empty", children: state.error ?? (state.harness ? `${harnessDisplayName(state.harness)} is listening. Say something.` : "No transcript yet.") }) : null,
|
|
1123
|
-
blocks.map((block, index) => /* @__PURE__ */ jsxs3(
|
|
1269
|
+
blocks.map((block, index) => /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
1124
1270
|
index === unreadBlock ? /* @__PURE__ */ jsx4("div", { class: "scui-unread-divider", role: "separator", "aria-label": "New messages", children: /* @__PURE__ */ jsx4("span", { children: "New" }) }) : null,
|
|
1125
1271
|
block.kind === "activity" ? /* @__PURE__ */ jsx4(Group, { value: block.entries, entries: block.entries, state, adapter }) : /* @__PURE__ */ jsx4(Entry, { value: block.entry, entry: block.entry, state, adapter })
|
|
1126
1272
|
] }, block.id)),
|
|
1127
1273
|
pendingMessage ? /* @__PURE__ */ jsxs3("article", { class: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, "aria-label": "Your pending message", children: [
|
|
1128
|
-
/* @__PURE__ */ jsx4(MessageImages, { items: pendingMessage.images }),
|
|
1274
|
+
/* @__PURE__ */ jsx4(MessageImages, { items: pendingMessage.images, adapter }),
|
|
1129
1275
|
/* @__PURE__ */ jsx4(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
|
|
1130
1276
|
/* @__PURE__ */ jsx4(ContextDisclosure, { context: pendingMessage.context }),
|
|
1131
1277
|
/* @__PURE__ */ jsxs3("footer", { children: [
|
|
@@ -1157,7 +1303,9 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
1157
1303
|
export {
|
|
1158
1304
|
ActivityGroup,
|
|
1159
1305
|
Conversation,
|
|
1306
|
+
ImageViewer,
|
|
1160
1307
|
LoadingStatus,
|
|
1308
|
+
MessageImages,
|
|
1161
1309
|
RequestCard,
|
|
1162
1310
|
SessionDetails,
|
|
1163
1311
|
TaskPlan,
|