blob: 00dbc9fc5c87e830cd1b3e83e8577f3866f2c8f6 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
<script lang="ts">
/**
* The `composer` view — the send box with the status derivation that used to
* live in App.svelte (error > queued > running > idle) and the
* send/queue/stop ports. Not conversation-scoped (no {#key}) — the composer
* is a persistent column fixture, exactly like today.
*/
import { Composer, type ComposerStatus } from "../../features/chat";
import { MESSAGE_QUEUE_RENDERER_ID, messageQueueCount } from "../../features/surface-host";
import type { AppViewPorts } from "../view-ports";
let { ports }: { ports: AppViewPorts } = $props();
const store = $derived(ports.store);
const queuedMessageCount = $derived(
store.activeConversationId === null
? undefined
: messageQueueCount(store.surface(MESSAGE_QUEUE_RENDERER_ID, store.activeConversationId)),
);
// Priority: error > queued > running > idle. `queued` (the turn is in flight
// but waiting for a concurrency slot — CR-13) wins over `running` so the
// corner shows a ring, not dots, during the wait. `turn-start` fires before
// the slot is granted, so `generating` is already true while
// `conversationStatus === "queued"`; the explicit queued check is what
// distinguishes the two.
const composerStatus = $derived.by<ComposerStatus>(() => {
if (store.activeChat.error) return "error";
const id = store.activeConversationId;
if (id !== null && store.conversationStatus(id) === "queued") return "queued";
return store.activeChat.generating ? "running" : "idle";
});
</script>
<Composer
onSend={(text, images) => store.send(text, images)}
onQueue={(text, images) => store.queueMessage(text, images)}
onStop={() => store.stopGeneration()}
contextSize={store.activeChat.currentContextSize}
contextWindow={store.modelInfo[store.activeModel]?.contextWindow}
{queuedMessageCount}
status={composerStatus}
/>
|