From 42a5af6c8f6998277cf69270ad12e2a64edac5d3 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 12 Mar 2026 15:17:36 -0500 Subject: feat(app): follow-up behavior (#17233) --- .../session/composer/session-composer-region.tsx | 26 +++++ .../session/composer/session-followup-dock.tsx | 109 +++++++++++++++++++++ .../pages/session/composer/session-revert-dock.tsx | 4 +- .../app/src/pages/session/message-timeline.tsx | 7 -- 4 files changed, 137 insertions(+), 9 deletions(-) create mode 100644 packages/app/src/pages/session/composer/session-followup-dock.tsx (limited to 'packages/app/src/pages/session') diff --git a/packages/app/src/pages/session/composer/session-composer-region.tsx b/packages/app/src/pages/session/composer/session-composer-region.tsx index 0cca90180..2034fbead 100644 --- a/packages/app/src/pages/session/composer/session-composer-region.tsx +++ b/packages/app/src/pages/session/composer/session-composer-region.tsx @@ -8,9 +8,11 @@ import { getSessionHandoff, setSessionHandoff } from "@/pages/session/handoff" import { useSessionKey } from "@/pages/session/session-layout" import { SessionPermissionDock } from "@/pages/session/composer/session-permission-dock" import { SessionQuestionDock } from "@/pages/session/composer/session-question-dock" +import { SessionFollowupDock } from "@/pages/session/composer/session-followup-dock" import { SessionRevertDock } from "@/pages/session/composer/session-revert-dock" import type { SessionComposerState } from "@/pages/session/composer/session-composer-state" import { SessionTodoDock } from "@/pages/session/composer/session-todo-dock" +import type { FollowupDraft } from "@/components/prompt-input/submit" export function SessionComposerRegion(props: { state: SessionComposerState @@ -21,6 +23,17 @@ export function SessionComposerRegion(props: { onNewSessionWorktreeReset: () => void onSubmit: () => void onResponseSubmit: () => void + followup?: { + queue: () => boolean + items: { id: string; text: string }[] + sending?: string + edit?: { id: string; prompt: FollowupDraft["prompt"]; context: FollowupDraft["context"] } + onQueue: (draft: FollowupDraft) => void + onAbort: () => void + onSend: (id: string) => void + onEdit: (id: string) => void + onEditLoaded: () => void + } revert?: { items: { id: string; text: string }[] restoring?: string @@ -214,10 +227,23 @@ export function SessionComposerRegion(props: { "margin-top": `${-lift()}px`, }} > + + + diff --git a/packages/app/src/pages/session/composer/session-followup-dock.tsx b/packages/app/src/pages/session/composer/session-followup-dock.tsx new file mode 100644 index 000000000..7d744f4e6 --- /dev/null +++ b/packages/app/src/pages/session/composer/session-followup-dock.tsx @@ -0,0 +1,109 @@ +import { For, Show, createMemo } from "solid-js" +import { createStore } from "solid-js/store" +import { Button } from "@opencode-ai/ui/button" +import { DockTray } from "@opencode-ai/ui/dock-surface" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { useLanguage } from "@/context/language" + +export function SessionFollowupDock(props: { + items: { id: string; text: string }[] + sending?: string + onSend: (id: string) => void + onEdit: (id: string) => void +}) { + const language = useLanguage() + const [store, setStore] = createStore({ + collapsed: false, + }) + + const toggle = () => setStore("collapsed", (value) => !value) + const total = createMemo(() => props.items.length) + const label = createMemo(() => + language.t(total() === 1 ? "session.followupDock.summary.one" : "session.followupDock.summary.other", { + count: total(), + }), + ) + const preview = createMemo(() => props.items[0]?.text ?? "") + + return ( + +
{ + if (event.key !== "Enter" && event.key !== " ") return + event.preventDefault() + toggle() + }} + > + {label()} + + {preview()} + +
+ { + event.preventDefault() + event.stopPropagation() + }} + onClick={(event) => { + event.stopPropagation() + toggle() + }} + aria-label={ + store.collapsed ? language.t("session.followupDock.expand") : language.t("session.followupDock.collapse") + } + /> +
+
+ + +