summaryrefslogtreecommitdiffhomepage
path: root/packages/desktop/src/pages
diff options
context:
space:
mode:
Diffstat (limited to 'packages/desktop/src/pages')
-rw-r--r--packages/desktop/src/pages/index.tsx108
1 files changed, 98 insertions, 10 deletions
diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx
index 929aeda7a..35e415aaf 100644
--- a/packages/desktop/src/pages/index.tsx
+++ b/packages/desktop/src/pages/index.tsx
@@ -548,7 +548,79 @@ export default function Page() {
<For each={local.session.userMessages()}>
{(message) => {
const diffs = createMemo(() => message.summary?.diffs ?? [])
- const working = createMemo(() => !message.summary?.title)
+ const working = createMemo(() => !message.summary?.body)
+ const assistantMessages = createMemo(() => {
+ return sync.data.message[activeSession().id]?.filter(
+ (m) => m.role === "assistant" && m.parentID == message.id,
+ ) as AssistantMessageType[]
+ })
+ const parts = createMemo(() =>
+ assistantMessages().flatMap((m) => sync.data.part[m.id]),
+ )
+ const lastPart = createMemo(() => parts().slice(-1)?.at(0))
+ const rawStatus = createMemo(() => {
+ const defaultStatus = "Working..."
+ const last = lastPart()
+ if (!last) return defaultStatus
+
+ if (last.type === "tool") {
+ switch (last.tool) {
+ case "task":
+ return "Delegating work..."
+ case "todowrite":
+ case "todoread":
+ return "Planning next steps..."
+ case "read":
+ return "Gathering context..."
+ case "list":
+ case "grep":
+ case "glob":
+ return "Searching the codebase..."
+ case "webfetch":
+ return "Searching the web..."
+ case "edit":
+ case "write":
+ return "Making edits..."
+ case "bash":
+ return "Running commands..."
+ default:
+ break
+ }
+ } else if (last.type === "reasoning") {
+ return "Thinking..."
+ } else if (last.type === "text") {
+ return "Gathering thoughts..."
+ }
+ return defaultStatus
+ })
+
+ const [status, setStatus] = createSignal(rawStatus())
+ let lastStatusChange = Date.now()
+ let statusTimeout: number | undefined
+
+ createEffect(() => {
+ const newStatus = rawStatus()
+ if (newStatus === status()) return
+
+ const timeSinceLastChange = Date.now() - lastStatusChange
+
+ if (timeSinceLastChange >= 1000) {
+ setStatus(newStatus)
+ lastStatusChange = Date.now()
+ if (statusTimeout) {
+ clearTimeout(statusTimeout)
+ statusTimeout = undefined
+ }
+ } else {
+ if (statusTimeout) clearTimeout(statusTimeout)
+ statusTimeout = setTimeout(() => {
+ setStatus(rawStatus())
+ lastStatusChange = Date.now()
+ statusTimeout = undefined
+ }, 1000 - timeSinceLastChange) as unknown as number
+ }
+ })
+
return (
<li class="group/li flex items-center self-stretch">
<button
@@ -570,7 +642,10 @@ export default function Page() {
"text-text-weak data-[active=true]:text-text-strong group-hover/li:text-text-base": true,
}}
>
- {message.summary?.title ?? local.session.getMessageText(message)}
+ <Switch>
+ <Match when={working()}>{status()}</Match>
+ <Match when={true}>{message.summary?.title}</Match>
+ </Switch>
</div>
</button>
</li>
@@ -604,10 +679,12 @@ export default function Page() {
// allowing time for the animations to finish
createEffect(() => {
+ title()
setTimeout(() => setTitled(!!title()), 10_000)
})
createEffect(() => {
- setTimeout(() => setCompleted(!!summary()), 3_000)
+ summary()
+ setTimeout(() => setCompleted(!!summary()), 1200)
})
return (
@@ -618,9 +695,18 @@ export default function Page() {
>
{/* Title */}
<div class="py-2 flex flex-col items-start gap-2 self-stretch sticky top-0 bg-background-stronger z-10">
- <div class="text-14-medium text-text-strong overflow-hidden text-ellipsis min-w-0">
- <Show when={titled()} fallback={<Typewriter as="h1" text={title()} />}>
- <h1>{title()}</h1>
+ <div class="w-full text-14-medium text-text-strong">
+ <Show
+ when={titled()}
+ fallback={
+ <Typewriter
+ as="h1"
+ text={title()}
+ class="overflow-hidden text-ellipsis min-w-0 text-nowrap"
+ />
+ }
+ >
+ <h1 class="overflow-hidden text-ellipsis min-w-0 text-nowrap">{title()}</h1>
</Show>
</div>
</div>
@@ -628,7 +714,7 @@ export default function Page() {
<Message message={message} parts={parts()} />
</div>
{/* Summary */}
- <Show when={!working()}>
+ <Show when={completed()}>
<div class="w-full flex flex-col gap-6 items-start self-stretch">
<div class="flex flex-col items-start gap-1 self-stretch">
<h2 class="text-12-medium text-text-weak">
@@ -637,7 +723,9 @@ export default function Page() {
<Match when={true}>Response</Match>
</Switch>
</h2>
- <Show when={summary()}>{(summary) => <Markdown text={summary()} />}</Show>
+ <Show when={summary()}>
+ {(summary) => <Markdown class="[&>*]:fade-up-text" text={summary()} />}
+ </Show>
</div>
<Accordion class="w-full" multiple>
<For each={diffs()}>
@@ -699,8 +787,8 @@ export default function Page() {
<div class="flex items-center gap-1 self-stretch">
<div class="text-12-medium">
<Switch>
- <Match when={expanded()}>Hide steps</Match>
- <Match when={!expanded()}>Show steps</Match>
+ <Match when={expanded()}>Hide details</Match>
+ <Match when={!expanded()}>Show details</Match>
</Switch>
</div>
<Collapsible.Arrow />