Skip to content

Commit f67a2f9

Browse files
committed
fix(web): hide image-only bootstrap prompt
1 parent bef1831 commit f67a2f9

4 files changed

Lines changed: 39 additions & 6 deletions

File tree

apps/web/src/components/ChatView.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ import {
183183
import {
184184
appendTerminalContextsToPrompt,
185185
formatTerminalContextLabel,
186+
IMAGE_ONLY_BOOTSTRAP_PROMPT,
186187
type TerminalContextDraft,
187188
type TerminalContextSelection,
188189
} from "../lib/terminalContext";
@@ -302,8 +303,6 @@ import {
302303
} from "../versionSkew";
303304
import { useAssetUrls } from "../assets/assetUrls";
304305

305-
const IMAGE_ONLY_BOOTSTRAP_PROMPT =
306-
"[User attached one or more images without additional text. Respond using the conversation context and the attached image(s).]";
307306
const EMPTY_ACTIVITIES: OrchestrationThreadActivity[] = [];
308307
const EMPTY_PROVIDERS: ServerProvider[] = [];
309308
const EMPTY_PROVIDER_SKILLS: ServerProvider["skills"] = [];

apps/web/src/components/chat/MessagesTimeline.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,9 @@ function UserTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "message"
930930
const userAudio = userAttachments.filter(
931931
(attachment): attachment is ChatAudioAttachment => attachment.type === "audio",
932932
);
933-
const displayedUserMessage = deriveDisplayedUserMessageState(row.message.text);
933+
const displayedUserMessage = deriveDisplayedUserMessageState(row.message.text, {
934+
hasImageAttachments: userImages.length > 0,
935+
});
934936
const terminalContexts = displayedUserMessage.contexts;
935937
const previewAnnotations: ParsedPreviewAnnotation[] = [];
936938
let visibleText = displayedUserMessage.visibleText;

apps/web/src/lib/terminalContext.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
formatInlineTerminalContextLabel,
1414
formatTerminalContextLabel,
1515
hasTerminalContextText,
16+
IMAGE_ONLY_BOOTSTRAP_PROMPT,
1617
INLINE_TERMINAL_CONTEXT_PLACEHOLDER,
1718
insertInlineTerminalContextPlaceholder,
1819
isTerminalContextExpired,
@@ -126,6 +127,27 @@ describe("terminalContext", () => {
126127
});
127128
});
128129

130+
it("hides the provider bootstrap prompt for image-only messages", () => {
131+
expect(
132+
deriveDisplayedUserMessageState(IMAGE_ONLY_BOOTSTRAP_PROMPT, {
133+
hasImageAttachments: true,
134+
}),
135+
).toEqual({
136+
visibleText: "",
137+
copyText: "",
138+
contextCount: 0,
139+
previewTitle: null,
140+
contexts: [],
141+
elementContexts: [],
142+
});
143+
});
144+
145+
it("preserves matching user text when no image is attached", () => {
146+
expect(deriveDisplayedUserMessageState(IMAGE_ONLY_BOOTSTRAP_PROMPT).visibleText).toBe(
147+
IMAGE_ONLY_BOOTSTRAP_PROMPT,
148+
);
149+
});
150+
129151
it("preserves prompt text when no trailing terminal context block exists", () => {
130152
expect(extractTrailingTerminalContexts("No attached context")).toEqual({
131153
promptText: "No attached context",

apps/web/src/lib/terminalContext.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ export interface ParsedTerminalContextEntry {
4343
}
4444

4545
export const INLINE_TERMINAL_CONTEXT_PLACEHOLDER = "\uFFFC";
46+
export const IMAGE_ONLY_BOOTSTRAP_PROMPT =
47+
"[User attached one or more images without additional text. Respond using the conversation context and the attached image(s).]";
4648

4749
const TRAILING_TERMINAL_CONTEXT_BLOCK_PATTERN =
4850
/\n*<terminal_context>\n([\s\S]*?)\n<\/terminal_context>\s*$/;
@@ -245,15 +247,23 @@ export function extractTrailingTerminalContexts(prompt: string): ExtractedTermin
245247
};
246248
}
247249

248-
export function deriveDisplayedUserMessageState(prompt: string): DisplayedUserMessageState {
250+
export function deriveDisplayedUserMessageState(
251+
prompt: string,
252+
options?: { readonly hasImageAttachments?: boolean },
253+
): DisplayedUserMessageState {
249254
// Order matters: send-time appends `<terminal_context>` first, then
250255
// `<element_context>` last. Strip element first so the (now-trailing)
251256
// terminal block can be matched by `extractTrailingTerminalContexts`.
252257
const extractedElement = extractTrailingElementContexts(prompt);
253258
const extractedTerminal = extractTrailingTerminalContexts(extractedElement.promptText);
259+
const normalizedVisibleText = extractedTerminal.promptText.trim();
260+
const hideImageOnlyBootstrapPrompt =
261+
options?.hasImageAttachments === true &&
262+
(normalizedVisibleText === IMAGE_ONLY_BOOTSTRAP_PROMPT ||
263+
normalizedVisibleText === `Ultrathink:\n${IMAGE_ONLY_BOOTSTRAP_PROMPT}`);
254264
return {
255-
visibleText: extractedTerminal.promptText,
256-
copyText: prompt,
265+
visibleText: hideImageOnlyBootstrapPrompt ? "" : extractedTerminal.promptText,
266+
copyText: hideImageOnlyBootstrapPrompt ? "" : prompt,
257267
contextCount: extractedTerminal.contextCount,
258268
previewTitle: extractedTerminal.previewTitle,
259269
contexts: extractedTerminal.contexts,

0 commit comments

Comments
 (0)