diff --git a/frontend/src/lib/components/sessions/SessionWrapper.svelte b/frontend/src/lib/components/sessions/SessionWrapper.svelte index e51445deeb..fc128584ba 100644 --- a/frontend/src/lib/components/sessions/SessionWrapper.svelte +++ b/frontend/src/lib/components/sessions/SessionWrapper.svelte @@ -79,17 +79,23 @@ import { goto } from '$lib/navigation' import { splitterPointerCapture } from '$lib/utils/splitterPointerCapture' import { StarterPrompts } from '$lib/components/copilot/chat/starter/starterPrompts.svelte' + import { resolvePreviewTab } from './previewRouter' + import { whereIs } from './sessionPreviewTabs.svelte' + import type { SessionPreviewTab } from './sessionState.svelte' let { sessionId, headerInPage = false, - covered = false + covered = false, + previewTabName }: { sessionId: string /** True for the session the page is showing: its header rides the page header bar. */ headerInPage?: boolean /** True while the page holds this wrapper inert under an overlay, where nothing takes focus. */ covered?: boolean + /** The name the preview's tab strip shows for a tab, without its side marker. */ + previewTabName: (tab: SessionPreviewTab) => string } = $props() // Parent keys by sessionId; this wrapper only mounts when the session exists. @@ -117,8 +123,25 @@ // Whether the first message goes out in Use. Not `permissions.readOnly`: before that send a // staged fork's session reads the workspace it forks, while the message builds in the fork. const heldInUse = $derived(!!workModeLock.current || runtime?.manager.workMode === AIWorkMode.USE) + // The item an unsent session opened on ("Open in AI session", or a tab opened before the + // first send): the chat reads the displayed tab with each message, so the empty chat asks + // about that item instead of greeting. What is on screen only: a collapsed panel hides it. + // Named as its tab is, so a deployed item in View mode gets its summary from the listing. + const previewedItem = $derived.by(() => { + if (!opensSession) return undefined + const tab = runtime?.previewTabs.displayedTab + if (!tab) return undefined + const slot = resolvePreviewTab(whereIs(tab)) + if (slot.kind !== 'editor' && slot.kind !== 'viewer') return undefined + const kind = slot.kind === 'editor' ? slot.editorKind : slot.viewerKind + return { + kind: kind === 'raw_app' ? 'app' : kind, + name: previewTabName(tab) + } + }) + const greets = $derived(opensSession && !previewedItem) const starterPrompts = new StarterPrompts( - () => (opensSession ? (actingWorkspaceId ?? $workspaceStore ?? undefined) : undefined), + () => (greets ? (actingWorkspaceId ?? $workspaceStore ?? undefined) : undefined), () => !heldInUse ) @@ -402,6 +425,13 @@ // utilities on one element resolve by stylesheet order, not attribute order. const bannerClass = 'flex flex-row items-center justify-between gap-2 py-2 px-3 text-xs border rounded-md' + + const previewedItemPlaceholder = $derived( + previewedItem && + (heldInUse + ? `Ask about the ${previewedItem.kind} ${previewedItem.name}, or run it…` + : `Ask about the ${previewedItem.kind} ${previewedItem.name}, or describe a change…`) + ) {#if !session || !runtime} @@ -409,7 +439,12 @@ {:else} - {#snippet sessionEmptyHint()}{/snippet} + {#snippet sessionEmptyHint()} + {#if previewedItem} + +
+ {/if} + {/snippet} {#snippet inputPreface()} {#if showRecoveryNotice} @@ -583,14 +618,14 @@ onDraftChange={(text) => setSessionDraftPrompt(sessionId, text)} initialAttachments={armedAtInit ? undefined : getSessionDraftAttachments(sessionId)} onAttachmentsChange={(a) => setSessionDraftAttachments(sessionId, a)} - placeholder={composerPlaceholder} + placeholder={previewedItemPlaceholder ?? composerPlaceholder} forceDisabled={isUnavailable || !!session.archived} forceDisabledMessage={isUnavailable ? 'This session is linked to a workspace that no longer exists. Move it or discard it from the banner above to keep working.' : session.archived ? 'This session is archived. Unarchive it from the banner above to keep working.' : ''} - starter={opensSession + starter={greets ? { where: 'session', suggestions: starterPrompts.suggestions } : undefined} viewTransitionNames={headerInPage && (opensSession || arrivingFromHomeSend())} @@ -604,37 +639,37 @@ its transcript area, its column, and its footer row's height; for a session that has never sent, the greeting above the centred composer. -->