@classic-homes/agent-chat 0.3.0 → 0.4.1
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 +5 -1
- package/dist/artifact-pages.d.ts +18 -0
- package/dist/artifact-pages.d.ts.map +1 -0
- package/dist/artifact-pages.js +89 -0
- package/dist/artifact-pages.test.d.ts +2 -0
- package/dist/artifact-pages.test.d.ts.map +1 -0
- package/dist/artifact-pages.test.js +102 -0
- package/dist/components/AgentChat.svelte +9 -0
- package/dist/components/AgentChat.svelte.d.ts +5 -0
- package/dist/components/AgentChat.svelte.d.ts.map +1 -1
- package/dist/components/ArtifactPanel.svelte +3 -6
- package/dist/components/ArtifactPanel.svelte.d.ts.map +1 -1
- package/dist/components/AssistantMessage.svelte +8 -1
- package/dist/components/AssistantMessage.svelte.d.ts +1 -0
- package/dist/components/AssistantMessage.svelte.d.ts.map +1 -1
- package/dist/components/Composer.svelte +221 -30
- package/dist/components/Composer.svelte.d.ts +8 -0
- package/dist/components/Composer.svelte.d.ts.map +1 -1
- package/dist/components/MessageItem.svelte +1 -0
- package/dist/components/MessageItem.svelte.d.ts +1 -0
- package/dist/components/MessageItem.svelte.d.ts.map +1 -1
- package/dist/components/MessageList.svelte +3 -0
- package/dist/components/MessageList.svelte.d.ts +1 -0
- package/dist/components/MessageList.svelte.d.ts.map +1 -1
- package/dist/components/ToolTimeline.svelte +138 -54
- package/dist/components/ToolTimeline.svelte.d.ts +11 -3
- package/dist/components/ToolTimeline.svelte.d.ts.map +1 -1
- package/dist/components/composer.svelte.test.d.ts +2 -0
- package/dist/components/composer.svelte.test.d.ts.map +1 -0
- package/dist/components/composer.svelte.test.js +162 -0
- package/dist/composer-keys.d.ts +3 -0
- package/dist/composer-keys.d.ts.map +1 -1
- package/dist/composer-keys.js +18 -0
- package/dist/composer-prompts.d.ts +16 -0
- package/dist/composer-prompts.d.ts.map +1 -0
- package/dist/composer-prompts.js +27 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/message-format.d.ts +28 -0
- package/dist/message-format.d.ts.map +1 -1
- package/dist/message-format.js +31 -0
- package/package.json +3 -3
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
The message box: an autosizing textarea in a card with attach, the host's context chip and
|
|
4
|
+
Send/Stop. Files can also be dropped on it or pasted. Typing `/` at the start opens the saved
|
|
5
|
+
prompt menu when the host passes `prompts`.
|
|
6
|
+
-->
|
|
1
7
|
<script lang="ts">
|
|
2
|
-
import { Button, Icon, Textarea } from '@classic-homes/theme-svelte';
|
|
8
|
+
import { cn, Button, Icon, Kbd, Popover, Spinner, Textarea } from '@classic-homes/theme-svelte';
|
|
3
9
|
import type { FileRef } from '@classic-homes/agent-contracts';
|
|
4
10
|
import { LIMITS } from '@classic-homes/agent-contracts';
|
|
5
|
-
import { composerKeyAction } from '../composer-keys.js';
|
|
11
|
+
import { composerKeyAction, promptMenuKeyAction } from '../composer-keys.js';
|
|
12
|
+
import { filterPrompts, promptQuery, type ComposerPrompt } from '../composer-prompts.js';
|
|
13
|
+
import { fileIcon, formatBytes } from '../message-format.js';
|
|
6
14
|
|
|
7
15
|
interface Props {
|
|
8
16
|
disabled?: boolean;
|
|
@@ -12,6 +20,8 @@
|
|
|
12
20
|
placeholder?: string;
|
|
13
21
|
/** Upload a file; the composer shows it as pending until the message is sent. */
|
|
14
22
|
upload?: (file: File) => Promise<FileRef>;
|
|
23
|
+
/** Saved prompts for the `/` menu; the menu is off without them. */
|
|
24
|
+
prompts?: ComposerPrompt[];
|
|
15
25
|
onsend?: (text: string) => void;
|
|
16
26
|
oncancel?: () => void;
|
|
17
27
|
onremovefile?: (fileId: string) => void;
|
|
@@ -25,28 +35,76 @@
|
|
|
25
35
|
files = $bindable([]),
|
|
26
36
|
placeholder = 'Ask Classic Agent…',
|
|
27
37
|
upload,
|
|
38
|
+
prompts,
|
|
28
39
|
onsend,
|
|
29
40
|
oncancel,
|
|
30
41
|
onremovefile,
|
|
31
42
|
context,
|
|
32
43
|
}: Props = $props();
|
|
33
44
|
|
|
45
|
+
const uid = $props.id();
|
|
34
46
|
let textarea = $state<HTMLTextAreaElement | null>(null);
|
|
47
|
+
let card: HTMLDivElement | undefined = $state();
|
|
35
48
|
let fileInput: HTMLInputElement | undefined = $state();
|
|
36
|
-
|
|
49
|
+
/** Files being uploaded right now, shown as chips with a spinner. */
|
|
50
|
+
let pending = $state<{ key: string; name: string; bytes: number; mimeType: string }[]>([]);
|
|
37
51
|
let uploadError = $state<string | undefined>();
|
|
52
|
+
let dragging = $state(false);
|
|
53
|
+
let dragDepth = 0;
|
|
38
54
|
|
|
39
55
|
export function focus(): void {
|
|
40
56
|
textarea?.focus({ preventScroll: true });
|
|
41
57
|
}
|
|
42
58
|
|
|
59
|
+
// `/` prompt menu
|
|
60
|
+
const query = $derived(prompts?.length ? promptQuery(value) : null);
|
|
61
|
+
const matches = $derived(query === null ? [] : filterPrompts(prompts ?? [], query));
|
|
62
|
+
let dismissedFor = $state<string | null>(null);
|
|
63
|
+
const menuOpen = $derived(query !== null && matches.length > 0 && dismissedFor !== value);
|
|
64
|
+
let active = $state(0);
|
|
65
|
+
let loadingPrompt = $state(false);
|
|
66
|
+
$effect(() => {
|
|
67
|
+
void query;
|
|
68
|
+
active = 0;
|
|
69
|
+
});
|
|
70
|
+
async function choose(prompt: ComposerPrompt | undefined): Promise<void> {
|
|
71
|
+
if (!prompt) return;
|
|
72
|
+
if (typeof prompt.text === 'string') value = prompt.text;
|
|
73
|
+
else {
|
|
74
|
+
loadingPrompt = true;
|
|
75
|
+
try {
|
|
76
|
+
value = await prompt.text();
|
|
77
|
+
} catch {
|
|
78
|
+
uploadError = `Could not load “${prompt.label}”`;
|
|
79
|
+
} finally {
|
|
80
|
+
loadingPrompt = false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
focus();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const chars = $derived(value.length);
|
|
87
|
+
const showCount = $derived(chars > LIMITS.messageChars * 0.8);
|
|
88
|
+
const busy = $derived(pending.length > 0 || loadingPrompt);
|
|
89
|
+
|
|
43
90
|
function submit(): void {
|
|
44
91
|
const text = value.trim();
|
|
45
|
-
if (!text || disabled || streaming ||
|
|
92
|
+
if (!text || disabled || streaming || busy) return;
|
|
46
93
|
value = '';
|
|
47
94
|
onsend?.(text);
|
|
48
95
|
}
|
|
49
96
|
function onkeydown(event: KeyboardEvent): void {
|
|
97
|
+
if (menuOpen) {
|
|
98
|
+
const menu = promptMenuKeyAction(event);
|
|
99
|
+
if (menu) {
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
if (menu === 'next') active = (active + 1) % matches.length;
|
|
102
|
+
else if (menu === 'previous') active = (active - 1 + matches.length) % matches.length;
|
|
103
|
+
else if (menu === 'choose') void choose(matches[active]);
|
|
104
|
+
else dismissedFor = value;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
50
108
|
const action = composerKeyAction(event, streaming);
|
|
51
109
|
if (action === 'send') {
|
|
52
110
|
event.preventDefault();
|
|
@@ -56,31 +114,70 @@
|
|
|
56
114
|
oncancel?.();
|
|
57
115
|
}
|
|
58
116
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const chosen = [...(input.files ?? [])];
|
|
62
|
-
input.value = '';
|
|
117
|
+
|
|
118
|
+
async function addFiles(chosen: File[]): Promise<void> {
|
|
63
119
|
if (!upload || chosen.length === 0) return;
|
|
64
120
|
uploadError = undefined;
|
|
65
121
|
for (const file of chosen) {
|
|
122
|
+
if (files.length + pending.length >= LIMITS.requestFiles) {
|
|
123
|
+
uploadError = `Attach up to ${LIMITS.requestFiles} files per message`;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
66
126
|
if (file.size > LIMITS.fileBytes) {
|
|
67
127
|
uploadError = `${file.name} is larger than ${Math.round(LIMITS.fileBytes / 1048576)} MB`;
|
|
68
128
|
continue;
|
|
69
129
|
}
|
|
70
|
-
|
|
130
|
+
const key = `${file.name}-${file.size}-${Math.random().toString(36).slice(2)}`;
|
|
131
|
+
pending = [...pending, { key, name: file.name, bytes: file.size, mimeType: file.type }];
|
|
71
132
|
try {
|
|
72
133
|
files = [...files, await upload(file)];
|
|
73
134
|
} catch (err) {
|
|
74
135
|
uploadError = err instanceof Error ? err.message : `Could not upload ${file.name}`;
|
|
75
136
|
} finally {
|
|
76
|
-
|
|
137
|
+
pending = pending.filter((p) => p.key !== key);
|
|
77
138
|
}
|
|
78
139
|
}
|
|
79
140
|
}
|
|
141
|
+
function onfiles(event: Event): void {
|
|
142
|
+
const input = event.currentTarget as HTMLInputElement;
|
|
143
|
+
const chosen = [...(input.files ?? [])];
|
|
144
|
+
input.value = '';
|
|
145
|
+
void addFiles(chosen);
|
|
146
|
+
}
|
|
147
|
+
function onpaste(event: ClipboardEvent): void {
|
|
148
|
+
const pasted = [...(event.clipboardData?.files ?? [])];
|
|
149
|
+
if (!upload || pasted.length === 0) return;
|
|
150
|
+
// Pasting a screenshot or a copied file attaches it; plain text pastes as usual.
|
|
151
|
+
event.preventDefault();
|
|
152
|
+
void addFiles(pasted);
|
|
153
|
+
}
|
|
154
|
+
const hasFiles = (event: DragEvent) => event.dataTransfer?.types.includes('Files') ?? false;
|
|
155
|
+
function ondragenter(event: DragEvent): void {
|
|
156
|
+
if (!upload || disabled || !hasFiles(event)) return;
|
|
157
|
+
event.preventDefault();
|
|
158
|
+
dragDepth += 1;
|
|
159
|
+
dragging = true;
|
|
160
|
+
}
|
|
161
|
+
function ondragover(event: DragEvent): void {
|
|
162
|
+
if (!upload || disabled || !hasFiles(event)) return;
|
|
163
|
+
event.preventDefault();
|
|
164
|
+
if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy';
|
|
165
|
+
}
|
|
166
|
+
function ondragleave(): void {
|
|
167
|
+
dragDepth = Math.max(0, dragDepth - 1);
|
|
168
|
+
if (dragDepth === 0) dragging = false;
|
|
169
|
+
}
|
|
170
|
+
function ondrop(event: DragEvent): void {
|
|
171
|
+
if (!upload || disabled || !hasFiles(event)) return;
|
|
172
|
+
event.preventDefault();
|
|
173
|
+
dragDepth = 0;
|
|
174
|
+
dragging = false;
|
|
175
|
+
void addFiles([...(event.dataTransfer?.files ?? [])]);
|
|
176
|
+
}
|
|
80
177
|
</script>
|
|
81
178
|
|
|
82
179
|
<form
|
|
83
|
-
class="bg-background px-4 pb-[max(0.75rem,env(safe-area-inset-bottom))] pt-2"
|
|
180
|
+
class="group/composer bg-background px-4 pb-[max(0.75rem,env(safe-area-inset-bottom))] pt-2"
|
|
84
181
|
onsubmit={(e) => {
|
|
85
182
|
e.preventDefault();
|
|
86
183
|
submit();
|
|
@@ -88,29 +185,58 @@
|
|
|
88
185
|
aria-label="Send a message"
|
|
89
186
|
>
|
|
90
187
|
<div
|
|
91
|
-
|
|
188
|
+
bind:this={card}
|
|
189
|
+
class={cn(
|
|
190
|
+
'relative mx-auto w-full max-w-3xl rounded-xl border border-input bg-background shadow-sm transition-shadow focus-within:border-ring focus-within:ring-2 focus-within:ring-ring/20',
|
|
191
|
+
dragging && 'border-primary ring-2 ring-primary/30',
|
|
192
|
+
)}
|
|
193
|
+
role="group"
|
|
194
|
+
aria-label="Message composer"
|
|
195
|
+
{ondragenter}
|
|
196
|
+
{ondragover}
|
|
197
|
+
{ondragleave}
|
|
198
|
+
{ondrop}
|
|
92
199
|
>
|
|
93
|
-
{#if
|
|
94
|
-
<div
|
|
200
|
+
{#if dragging}
|
|
201
|
+
<div
|
|
202
|
+
class="pointer-events-none absolute inset-0 z-10 flex items-center justify-center gap-2 rounded-xl bg-background/90 text-sm font-medium text-primary"
|
|
203
|
+
>
|
|
204
|
+
<Icon name="paperclip" size={16} /> Drop files to attach
|
|
205
|
+
</div>
|
|
206
|
+
{/if}
|
|
207
|
+
{#if files.length || pending.length || uploadError}
|
|
208
|
+
<ul class="flex flex-wrap items-center gap-1.5 px-3 pt-3 text-xs" aria-label="Attachments">
|
|
95
209
|
{#each files as file (file.fileId)}
|
|
96
|
-
<
|
|
97
|
-
class="inline-flex max-w-
|
|
210
|
+
<li
|
|
211
|
+
class="inline-flex max-w-60 items-center gap-1.5 rounded-md border border-border bg-background py-1 pl-2 pr-0.5"
|
|
98
212
|
>
|
|
99
|
-
<Icon name=
|
|
213
|
+
<Icon name={fileIcon(file.mimeType)} size={14} class="shrink-0 text-muted-foreground" />
|
|
100
214
|
<span class="truncate">{file.name}</span>
|
|
101
|
-
<
|
|
215
|
+
<span class="shrink-0 text-muted-foreground">{formatBytes(file.bytes)}</span>
|
|
216
|
+
<Button
|
|
102
217
|
type="button"
|
|
103
|
-
|
|
218
|
+
variant="ghost"
|
|
219
|
+
size="icon"
|
|
220
|
+
class="size-6 shrink-0 text-muted-foreground"
|
|
104
221
|
aria-label={`Remove ${file.name}`}
|
|
105
222
|
onclick={() => {
|
|
106
223
|
files = files.filter((f) => f.fileId !== file.fileId);
|
|
107
224
|
onremovefile?.(file.fileId);
|
|
108
|
-
}}><Icon name="close" size={12} /></
|
|
225
|
+
}}><Icon name="close" size={12} /></Button
|
|
109
226
|
>
|
|
110
|
-
</
|
|
227
|
+
</li>
|
|
111
228
|
{/each}
|
|
112
|
-
{#
|
|
113
|
-
|
|
229
|
+
{#each pending as file (file.key)}
|
|
230
|
+
<li
|
|
231
|
+
class="inline-flex max-w-60 items-center gap-1.5 rounded-md border border-dashed border-border py-1 pl-2 pr-2 text-muted-foreground"
|
|
232
|
+
>
|
|
233
|
+
<Spinner size="sm" label={`Uploading ${file.name}`} class="shrink-0" />
|
|
234
|
+
<span class="truncate">{file.name}</span>
|
|
235
|
+
<span class="shrink-0">{formatBytes(file.bytes)}</span>
|
|
236
|
+
</li>
|
|
237
|
+
{/each}
|
|
238
|
+
{#if uploadError}<li class="text-destructive" role="alert">{uploadError}</li>{/if}
|
|
239
|
+
</ul>
|
|
114
240
|
{/if}
|
|
115
241
|
<Textarea
|
|
116
242
|
bind:ref={textarea}
|
|
@@ -122,8 +248,14 @@
|
|
|
122
248
|
{placeholder}
|
|
123
249
|
aria-label="Message"
|
|
124
250
|
maxlength={LIMITS.messageChars}
|
|
251
|
+
role={prompts?.length ? 'combobox' : undefined}
|
|
252
|
+
aria-autocomplete={prompts?.length ? 'list' : undefined}
|
|
253
|
+
aria-expanded={prompts?.length ? menuOpen : undefined}
|
|
254
|
+
aria-controls={menuOpen ? `${uid}-prompts` : undefined}
|
|
255
|
+
aria-activedescendant={menuOpen ? `${uid}-prompt-${active}` : undefined}
|
|
125
256
|
{disabled}
|
|
126
257
|
{onkeydown}
|
|
258
|
+
{onpaste}
|
|
127
259
|
/>
|
|
128
260
|
<div class="flex items-center gap-1 px-2 pb-2">
|
|
129
261
|
{#if upload}
|
|
@@ -134,22 +266,31 @@
|
|
|
134
266
|
size="icon"
|
|
135
267
|
class="size-8 text-muted-foreground"
|
|
136
268
|
aria-label="Attach files"
|
|
137
|
-
disabled={disabled ||
|
|
138
|
-
loading={uploading > 0}
|
|
269
|
+
disabled={disabled || files.length >= LIMITS.requestFiles}
|
|
139
270
|
onclick={() => fileInput?.click()}
|
|
140
271
|
>
|
|
141
|
-
|
|
272
|
+
<Icon name="paperclip" size={18} />
|
|
142
273
|
</Button>
|
|
143
274
|
{/if}
|
|
144
275
|
{#if context}<div class="min-w-0">{@render context()}</div>{/if}
|
|
145
|
-
<div class="ml-auto">
|
|
276
|
+
<div class="ml-auto flex items-center gap-2">
|
|
277
|
+
{#if showCount}
|
|
278
|
+
<span
|
|
279
|
+
class={cn(
|
|
280
|
+
'text-xs tabular-nums text-muted-foreground',
|
|
281
|
+
chars >= LIMITS.messageChars && 'text-destructive',
|
|
282
|
+
)}
|
|
283
|
+
aria-live="polite"
|
|
284
|
+
>{chars.toLocaleString()} / {LIMITS.messageChars.toLocaleString()}</span
|
|
285
|
+
>
|
|
286
|
+
{/if}
|
|
146
287
|
{#if streaming}
|
|
147
288
|
<Button
|
|
148
289
|
type="button"
|
|
149
290
|
variant="outline"
|
|
150
291
|
size="icon"
|
|
151
292
|
class="size-8"
|
|
152
|
-
aria-label="Stop"
|
|
293
|
+
aria-label="Stop (Esc)"
|
|
153
294
|
onclick={() => oncancel?.()}><Icon name="stop" size={14} /></Button
|
|
154
295
|
>
|
|
155
296
|
{:else}
|
|
@@ -158,11 +299,61 @@
|
|
|
158
299
|
size="icon"
|
|
159
300
|
class="size-8"
|
|
160
301
|
aria-label="Send"
|
|
161
|
-
disabled={disabled || !value.trim() ||
|
|
162
|
-
><Icon name="send" size={16} /></Button
|
|
302
|
+
disabled={disabled || !value.trim() || busy}><Icon name="send" size={16} /></Button
|
|
163
303
|
>
|
|
164
304
|
{/if}
|
|
165
305
|
</div>
|
|
166
306
|
</div>
|
|
167
307
|
</div>
|
|
308
|
+
<p
|
|
309
|
+
class="mx-auto mt-1.5 hidden max-w-3xl items-center gap-1.5 px-1 text-[11px] text-muted-foreground opacity-0 transition-opacity group-focus-within/composer:opacity-100 sm:flex"
|
|
310
|
+
aria-hidden="true"
|
|
311
|
+
>
|
|
312
|
+
{#if streaming}
|
|
313
|
+
<Kbd size="sm">Esc</Kbd> to stop
|
|
314
|
+
{:else}
|
|
315
|
+
<Kbd size="sm">Enter</Kbd> to send · <Kbd keys={['Shift', 'Enter']} size="sm" /> for a new line
|
|
316
|
+
{#if prompts?.length}· <Kbd size="sm">/</Kbd> for saved prompts{/if}
|
|
317
|
+
{/if}
|
|
318
|
+
</p>
|
|
168
319
|
</form>
|
|
320
|
+
|
|
321
|
+
{#if prompts?.length}
|
|
322
|
+
<Popover
|
|
323
|
+
open={menuOpen}
|
|
324
|
+
onOpenChange={(next) => {
|
|
325
|
+
if (!next) dismissedFor = value;
|
|
326
|
+
}}
|
|
327
|
+
anchor={card ?? null}
|
|
328
|
+
side="top"
|
|
329
|
+
align="start"
|
|
330
|
+
sideOffset={6}
|
|
331
|
+
autoFocus={false}
|
|
332
|
+
aria-label="Saved prompts"
|
|
333
|
+
class="w-[min(28rem,calc(100vw-2rem))] p-1"
|
|
334
|
+
>
|
|
335
|
+
<ul id={`${uid}-prompts`} role="listbox" aria-label="Saved prompts" class="grid gap-0.5">
|
|
336
|
+
{#each matches as prompt, i (prompt.id)}
|
|
337
|
+
<!-- Keyboard choice happens in the textarea (combobox + aria-activedescendant). -->
|
|
338
|
+
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
339
|
+
<li
|
|
340
|
+
id={`${uid}-prompt-${i}`}
|
|
341
|
+
role="option"
|
|
342
|
+
aria-selected={i === active}
|
|
343
|
+
class={cn(
|
|
344
|
+
'cursor-pointer rounded-md px-2.5 py-1.5 text-sm',
|
|
345
|
+
i === active ? 'bg-muted text-foreground' : 'text-foreground hover:bg-muted/60',
|
|
346
|
+
)}
|
|
347
|
+
onpointerdown={(e) => e.preventDefault()}
|
|
348
|
+
onclick={() => void choose(prompt)}
|
|
349
|
+
onpointermove={() => (active = i)}
|
|
350
|
+
>
|
|
351
|
+
<span class="block truncate font-medium">{prompt.label}</span>
|
|
352
|
+
{#if prompt.description}
|
|
353
|
+
<span class="block truncate text-xs text-muted-foreground">{prompt.description}</span>
|
|
354
|
+
{/if}
|
|
355
|
+
</li>
|
|
356
|
+
{/each}
|
|
357
|
+
</ul>
|
|
358
|
+
</Popover>
|
|
359
|
+
{/if}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FileRef } from '@classic-homes/agent-contracts';
|
|
2
|
+
import { type ComposerPrompt } from '../composer-prompts.js';
|
|
2
3
|
interface Props {
|
|
3
4
|
disabled?: boolean;
|
|
4
5
|
streaming?: boolean;
|
|
@@ -7,12 +8,19 @@ interface Props {
|
|
|
7
8
|
placeholder?: string;
|
|
8
9
|
/** Upload a file; the composer shows it as pending until the message is sent. */
|
|
9
10
|
upload?: (file: File) => Promise<FileRef>;
|
|
11
|
+
/** Saved prompts for the `/` menu; the menu is off without them. */
|
|
12
|
+
prompts?: ComposerPrompt[];
|
|
10
13
|
onsend?: (text: string) => void;
|
|
11
14
|
oncancel?: () => void;
|
|
12
15
|
onremovefile?: (fileId: string) => void;
|
|
13
16
|
/** Slot for a host-provided context chip (page context toggle). */
|
|
14
17
|
context?: import('svelte').Snippet;
|
|
15
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* The message box: an autosizing textarea in a card with attach, the host's context chip and
|
|
21
|
+
* Send/Stop. Files can also be dropped on it or pasted. Typing `/` at the start opens the saved
|
|
22
|
+
* prompt menu when the host passes `prompts`.
|
|
23
|
+
*/
|
|
16
24
|
declare const Composer: import("svelte").Component<Props, {
|
|
17
25
|
focus: () => void;
|
|
18
26
|
}, "value" | "files">;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Composer.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/Composer.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"Composer.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/Composer.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAG9D,OAAO,EAA8B,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAIvF,UAAU,KAAK;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,oEAAoE;IACpE,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAC;CACpC;AA2PH;;;;GAIG;AACH,QAAA,MAAM,QAAQ;iBA/NO,IAAI;qBA+N6B,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageItem.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/MessageItem.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAK/C,UAAU,KAAK;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACtE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAkBH,sEAAsE;AACtE,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"MessageItem.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/MessageItem.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAK/C,UAAU,KAAK;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACtE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAkBH,sEAAsE;AACtE,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
streaming: boolean;
|
|
11
11
|
sandboxOrigin: string;
|
|
12
12
|
fileUrl: (fileId: string) => string;
|
|
13
|
+
toolLabels?: Record<string, string>;
|
|
13
14
|
onnavigate?: (href: string) => void;
|
|
14
15
|
onopenartifact?: (artifactId: string) => void;
|
|
15
16
|
onprompt?: (text: string) => void;
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
streaming,
|
|
25
26
|
sandboxOrigin,
|
|
26
27
|
fileUrl,
|
|
28
|
+
toolLabels,
|
|
27
29
|
onnavigate,
|
|
28
30
|
onopenartifact,
|
|
29
31
|
onprompt,
|
|
@@ -133,6 +135,7 @@
|
|
|
133
135
|
streaming={streaming && i === messages.length - 1 && message.role === 'assistant'}
|
|
134
136
|
{sandboxOrigin}
|
|
135
137
|
{fileUrl}
|
|
138
|
+
{toolLabels}
|
|
136
139
|
{onnavigate}
|
|
137
140
|
{onopenartifact}
|
|
138
141
|
{onprompt}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/MessageList.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAK/C,UAAU,KAAK;IACb,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACtE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAC;CAClC;
|
|
1
|
+
{"version":3,"file":"MessageList.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/MessageList.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAK/C,UAAU,KAAK;IACb,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACtE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAC;CAClC;AA4HH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|