@@ -20,13 +20,16 @@ import {
2020 scrollFadeClass ,
2121 useScrollEdges ,
2222} from '@sim/emcn'
23+ import { Calendar , Clock } from '@sim/emcn/icons'
2324import { useQueryClient } from '@tanstack/react-query'
2425import { defaultRangeExtractor , type Range , useVirtualizer } from '@tanstack/react-virtual'
26+ import { useParams } from 'next/navigation'
2527import {
2628 AssistantActionReviewMessage ,
2729 useHasAssistantActionReview ,
2830} from '@/components/assistant-actions'
2931import { SMOOTH_CHASE_RATE } from '@/lib/core/utils/smooth-bottom-chase'
32+ import { parseAutomatedTurn } from '@/lib/mothership/chat/automated-turn'
3033import type { TurnOrigin } from '@/lib/mothership/generated/protocol'
3134import { inter } from '@/app/_styles/fonts/inter/inter'
3235import { FindBar } from '@/app/workspace/[workspaceId]/components/find-bar'
@@ -49,6 +52,7 @@ import {
4952 parseLastQuestionTag ,
5053} from '@/app/workspace/[workspaceId]/home/components/message-content/components/special-tags'
5154import type { SearchIntegrationConnectionProps } from '@/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/search-integration-connection'
55+ import { watchLabel } from '@/app/workspace/[workspaceId]/home/components/message-content/components/watch-activity/watch-activity'
5256import {
5357 prepareCopyableMarkdown ,
5458 toCopyableMarkdown ,
@@ -62,6 +66,7 @@ import {
6266} from '@/app/workspace/[workspaceId]/home/components/user-input'
6367import type { ModelSelectorOptions } from '@/app/workspace/[workspaceId]/home/components/user-input/components/model-selector'
6468import { UserMessageContent } from '@/app/workspace/[workspaceId]/home/components/user-message-content'
69+ import { useResourceNameRevision } from '@/app/workspace/[workspaceId]/home/hooks/use-tool-resource-titles'
6570import {
6671 fetchWorkspaceResourceRef ,
6772 readCachedWorkspaceResourceRef ,
@@ -204,37 +209,55 @@ interface UserMessageRowProps {
204209 attachmentWidthClassName : string
205210}
206211
212+ function describeAutomatedTurn (
213+ origin : TurnOrigin ,
214+ content : string ,
215+ workspaceId ?: string
216+ ) : { label : string ; text : string ; note ?: string } {
217+ const turn = parseAutomatedTurn ( origin , content )
218+ if ( turn ?. origin === 'task' ) {
219+ return {
220+ label : 'Background task' ,
221+ text : watchLabel ( turn . task , workspaceId ) ,
222+ note : turn . task . note || undefined ,
223+ }
224+ }
225+ if ( turn ?. origin === 'job' ) return { label : `Scheduled job · ${ turn . run } ` , text : turn . title }
226+ return origin === 'task'
227+ ? { label : 'Background task' , text : 'Task finished' }
228+ : { label : 'Scheduled job' , text : 'Run started' }
229+ }
230+
207231/**
208- * A turn automation opened, never a user bubble — the user did not type it : a muted system chip
209- * with one line . A background- task notification (mothership 21-background-tasks.md §6.4) shows
210- * its outcome line; a scheduled job's run shows the brief's first line (the job and its run) .
232+ * A turn automation opened (mothership 21-background-tasks.md §6.4) : a message in the user's
233+ * lane, labeled with what sent it . A background task shows the same line as its watch row; a
234+ * scheduled job shows its title and run.
211235 */
212236interface AutomatedTurnRowProps {
213237 origin : TurnOrigin
214238 content : string
215239 rowClassName : string
240+ bubbleClassName : string
216241}
217242
218243const AutomatedTurnRow = memo ( function AutomatedTurnRow ( {
219244 origin,
220245 content,
221246 rowClassName,
247+ bubbleClassName,
222248} : AutomatedTurnRowProps ) {
223- const lines = content . split ( '\n' ) . filter ( ( line ) => line . length > 0 )
224- const summary =
225- origin === 'task'
226- ? ( lines . find ( ( line ) => line . startsWith ( 'Task ' ) ) ?? lines [ lines . length - 1 ] ?? '' ) . replace (
227- / ^ T a s k [ 0 - 9 a - f - ] + / ,
228- ''
229- )
230- : ( lines [ 0 ] ?? '' ) . replace ( / ^ J o b : / , '' )
249+ const params = useParams < { workspaceId ?: string } > ( )
250+ useResourceNameRevision ( )
251+ const { label, text, note } = describeAutomatedTurn ( origin , content , params ?. workspaceId )
252+ const Icon = origin === 'task' ? Clock : Calendar
231253 return (
232- < div className = { cn ( 'flex w-full justify-center' , rowClassName ) } >
233- < div className = 'max-w-[85%] rounded-full border border-[var(--border)] bg-[var(--bg)] px-3 py-1 text-[12px] text-[var(--text-secondary)]' >
234- < span className = 'mr-1.5 font-medium text-[var(--text-primary)]' >
235- { origin === 'task' ? 'Background task' : 'Scheduled job' }
236- </ span >
237- { summary }
254+ < div className = { rowClassName } >
255+ < div className = 'flex items-center gap-1.5 text-[var(--text-muted)] text-caption' >
256+ < Icon className = 'size-[12px] text-[var(--text-icon)]' />
257+ { label }
258+ </ div >
259+ < div className = { bubbleClassName } title = { note } >
260+ < UserMessageContent content = { text } />
238261 </ div >
239262 </ div >
240263 )
@@ -995,7 +1018,8 @@ export function MothershipChat({
9951018 < AutomatedTurnRow
9961019 origin = { msg . origin }
9971020 content = { msg . content }
998- rowClassName = { styles . rowGap }
1021+ rowClassName = { cn ( styles . userRow , styles . rowGap ) }
1022+ bubbleClassName = { styles . userBubble }
9991023 />
10001024 ) : (
10011025 < UserMessageRow
0 commit comments