diff --git a/src/server/agent/session-manager.ts b/src/server/agent/session-manager.ts index ccc79b675..5ccf87a62 100755 --- a/src/server/agent/session-manager.ts +++ b/src/server/agent/session-manager.ts @@ -7167,9 +7167,9 @@ export class SessionManager { }; try { const continuationPrompt = - "[SYSTEM: The infrastructure server restarted while you were mid-turn. " + + "The infrastructure server restarted while you were mid-turn. " + "Your previous work has been preserved. Please continue where you left off. " + - "Do NOT start over — review your recent messages and resume from the exact point of interruption.]"; + "Do NOT start over — review your recent messages and resume from the exact point of interruption."; await dispatchTrackedSystemPrompt(session, continuationPrompt, { source: "system", whenReady: true, diff --git a/src/ui/app.css b/src/ui/app.css index 1c1e5a8ef..d19a25ec9 100644 --- a/src/ui/app.css +++ b/src/ui/app.css @@ -4009,6 +4009,7 @@ html { align-items: flex-end; min-width: 0; max-width: 100%; + padding-top: 2px; } .prompt-bubble-shell { @@ -4030,12 +4031,13 @@ html { width: fit-content; min-width: 0; max-width: 100%; - margin-top: 7px; + /* Keep the floating badge fully inside paint containment while overlapping the bubble. */ + margin-top: 14px; padding-top: 14px; } .user-message-container--labelled::before { - top: 18px; + top: 19px; } .prompt-author-badge { @@ -4048,27 +4050,68 @@ html { width: max-content; max-width: calc(100% - 18px); min-width: 0; - min-height: 22px; + height: 24px; margin-left: 10px; padding: 1px 7px 1px 3px; - transform: translateY(-56%); border: 1px solid var(--border); border-radius: 6px; background: var(--card); - box-shadow: 0 2px 5px color-mix(in oklch, var(--foreground) 9%, transparent); + box-shadow: 0 1px 4px color-mix(in oklch, var(--foreground) 8%, transparent); color: var(--muted-foreground); + line-height: 1; +} + +.prompt-author-badge:not(.prompt-author-badge--link) { pointer-events: none; } +.prompt-author-badge--link { + cursor: pointer; + text-decoration: none; + transition: border-color 120ms ease, box-shadow 120ms ease; +} + +.prompt-author-badge--link:hover { + border-color: color-mix(in oklch, var(--primary) 40%, var(--border)); + box-shadow: 0 1px 5px color-mix(in oklch, var(--foreground) 12%, transparent); +} + +.prompt-author-badge--link:focus-visible { + outline: 2px solid var(--ring); + outline-offset: 2px; +} + .prompt-author-avatar { display: grid; place-items: center; flex: none; width: 20px; - height: 17px; + height: 20px; overflow: visible; } +.prompt-author-avatar > span { + display: contents; +} + +.prompt-author-initial { + display: grid; + place-items: center; + flex: none; + width: 16px; + height: 16px; + border: 1px solid var(--border); + border-radius: 4px; + background: var(--secondary); + color: var(--secondary-foreground); + font-size: 7px; + font-weight: 850; +} + +.prompt-author-initial::before { + content: attr(data-initial); +} + .prompt-author-name { flex: 1 1 auto; min-width: 0; @@ -4078,6 +4121,7 @@ html { color: var(--foreground); font-size: 10px; font-weight: 670; + line-height: 1.3; } .prompt-author-divider, @@ -4086,7 +4130,11 @@ html { } .prompt-author-divider { - color: var(--border); + width: 1px; + height: 12px; + overflow: hidden; + background: var(--border); + color: transparent; } .prompt-author-kind { diff --git a/src/ui/bobbit-render.ts b/src/ui/bobbit-render.ts index a7a6f1323..399c95e7d 100644 --- a/src/ui/bobbit-render.ts +++ b/src/ui/bobbit-render.ts @@ -57,6 +57,8 @@ export interface SidebarBobbitOptions { unread?: boolean; /** Disable the idle breathing loop for actual sidebar session/staff rows. */ disableIdleBreathing?: boolean; + /** Center the complete sprite group in its fixed-width container. */ + centerInContainer?: boolean; } // ============================================================================ @@ -675,13 +677,14 @@ export function renderStaticSidebarBobbitCanvas(opts: { unread: false, noDesaturate: true, disableIdleBreathing: true, + centerInContainer: true, hueRotate: opts.hueRotate, accessory: opts.accessory, })}`; } export function renderSidebarBobbitCanvas(opts: SidebarBobbitOptions): TemplateResult { - const { status, isCompacting = false, hueRotate = 0, isSelected = false, isAborting = false, noDesaturate = false, unread = false, disableIdleBreathing = false } = opts; + const { status, isCompacting = false, hueRotate = 0, isSelected = false, isAborting = false, noDesaturate = false, unread = false, disableIdleBreathing = false, centerInContainer = false } = opts; const acc = opts.accessory ?? NO_ACCESSORY; const hasAccessory = acc.id !== "none"; const addsHeight = acc.addsHeight; @@ -797,8 +800,8 @@ export function renderSidebarBobbitCanvas(opts: SidebarBobbitOptions): TemplateR let accCssW = 0; let accCssH = 0; let accLeft = 0; - let sidebarOriginX = 0; const sidebarContainerWidth = 20; + let sidebarOriginX = centerInContainer ? (sidebarContainerWidth - cssW) / 2 : 0; if (hasAccessory) { const spriteData = SPRITE_ACCESSORIES[acc.id]; if (spriteData && spriteData.pixels.length > 0) { @@ -814,11 +817,10 @@ export function renderSidebarBobbitCanvas(opts: SidebarBobbitOptions): TemplateR const srcW = maxX - xShift + 1; const srcH = maxY - yShift + 1; - // Preserve coordinate alignment between body + accessory, but use spare - // sidebar wrapper width when an accessory has left-of-body pixels (e.g. - // headset at x=-1). Other accessories keep the historical x=0 body origin - // so right-hand tools don't shift further into the clipped edge. - if (xShift < 0) { + // Preserve coordinate alignment between body + accessory. Static author + // avatars center the complete group; sidebar rows retain their historical + // left alignment except for accessories with left-of-body pixels. + if (centerInContainer || xShift < 0) { const groupRight = Math.max(BODY_WIDTH, maxX + 1); const groupWidth = (groupRight - xShift) * S; const groupLeft = groupWidth <= sidebarContainerWidth diff --git a/src/ui/components/Messages.ts b/src/ui/components/Messages.ts index 121f7c601..fa5b36bd7 100644 --- a/src/ui/components/Messages.ts +++ b/src/ui/components/Messages.ts @@ -308,28 +308,47 @@ export class UserMessage extends LitElement { } const isAgent = presentation.kind === "agent"; + const authorBadgeContent = isAgent ? html` + + + + + ` : html` + + + `; + const originSessionId = isAgent ? this.authorAppearance?.sessionId : undefined; + const authorBadge = originSessionId ? html` + + ${authorBadgeContent} + + ` : html` +
+ `; return html`