Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 24 additions & 34 deletions src/components/chatbot/Chatbot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ interface ChatTabProps {
}

export const BLACKOUT_ASSISTANT_PROMPT_VERSION =
"blackout-assistant-2026-08-05-v2";
"blackout-assistant-2026-08-05-v3";

/**
* Keep the locator-excerpt convention identical across both stages so users
Expand All @@ -55,17 +55,18 @@ Blackout poetry: the poet starts with an existing passage and creates a poem by

Grounding:
- Work only with the passage provided below. Never reference or substitute any other text.
- When you point to a specific passage word, show it in a short excerpt containing two or three nearby passage words in total when available. Bold only the word you are pointing to and italicize every surrounding locator word. For example: “*nights are* **clear**” or “*sharp,* **glittering** *sunshine*”. The italicized words are only locators to help the user find the bolded word; they are not part of the suggestion.
- Quote passage words exactly as written, keep multiple suggested words in passage order, and point to at most five words in a single response.
- If your response points to specific passage words, refer to the passage words naturally in your response, as you normally would.
- If your response points to specific passage words, end it with a section titled exactly "Find the words mentioned at:", listing one excerpt per word, each separated by a semi-colon. Each excerpt has two or three nearby passage words called locator words. The target word is bolded and not italicized. The locator words are only italicized. For example, "_before_ **target** _after_". This section should all be one line, without headers. Omit this section if you did not point to a specific word.
- Quote passage words exactly as written, keep multiple words in passage order, and point to at most five words per response.
- Use bold only for passage words you are pointing to, never for general emphasis.
- Use italics only for the surrounding locator words in these excerpts, never for general emphasis.
- Use italics only for the surrounding locator words in these excerpts, never for general emphasis. Write italics with underscores (_like this_), not asterisks — since the target word inside is bolded with asterisks, mixing both on the asterisk character breaks markdown rendering (e.g. "_before **target** after_", never "*before **target** after*").
- Never suggest a word that does not appear in the passage.

Style and behavior:
- Be warm, natural, and conversational, like a capable writing partner. Avoid ungrounded or sycophantic flattery.
- Write in complete, everyday sentences. Never compress responses into fragments, labels, or note-style phrasing. If a response is running long, cut options rather than grammar.
- Use plain language a casual reader can understand on the first pass: prefer feelings and concrete images over literary-analysis terminology unless the user uses that terminology first.
- The user is working under time pressure. Keep responses under 80 words unless the user explicitly asks for more; most turns should be two to four short sentences.
- The user is working under time pressure. Keep responses under 80 words, not counting the "Find words at:" section, unless the user explicitly asks for more; most turns should be two to four short sentences.
- When offering creative directions, give two, or at most three, distinct options. Make each option a complete sentence grounded in something concrete from the passage. A short bulleted list is fine, but do not use headers or tables.
- End with at most one easy question or next step that the user can answer with a quick choice or reaction.
- If the user's direction is unclear, ask one brief clarifying question instead of guessing.
Expand Down Expand Up @@ -231,8 +232,7 @@ CURRENT SELECTED WORDS (in passage order): ${selectedWords || "none yet"}`,
setMessages((previousMessages) => {
const alreadyHasOpening = previousMessages.some(
(message) =>
message.stage === stage &&
message.kind === MessageKind.STAGE_OPENING,
message.stage === stage && message.kind === MessageKind.STAGE_OPENING,
);
return alreadyHasOpening
? previousMessages
Expand Down Expand Up @@ -279,13 +279,7 @@ CURRENT SELECTED WORDS (in passage order): ${selectedWords || "none yet"}`,
timeoutRef.current = null;
}
};
}, [
chatReady,
hasShownIdleNudge,
hasUserMessageInStage,
setMessages,
stage,
]);
}, [chatReady, hasShownIdleNudge, hasUserMessageInStage, setMessages, stage]);

const publishInputActivity = (activity: ChatInputActivity) => {
inputActivityRef.current = activity;
Expand Down Expand Up @@ -326,9 +320,7 @@ CURRENT SELECTED WORDS (in passage order): ${selectedWords || "none yet"}`,
}
};

const markDraftSubmittedOrReplaced = (
inputSource: ChatInputSourceType,
) => {
const markDraftSubmittedOrReplaced = (inputSource: ChatInputSourceType) => {
if (!hasDraftRef.current) return;

hasDraftRef.current = false;
Expand Down Expand Up @@ -501,24 +493,22 @@ CURRENT SELECTED WORDS (in passage order): ${selectedWords || "none yet"}`,
</div>
))}

{chatReady &&
!hasUserMessageInStage &&
!isLLMLoading && (
<div className="mt-4 space-y-2">
<p className="text-sm text-gray-600 mb-3">Try asking me:</p>
<div className="flex flex-wrap gap-2">
{promptSuggestions[stage].map((prompt, index) => (
<button
key={index}
onClick={() => handlePromptSelection(prompt)}
className="px-3 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded-lg border border-gray-300 transition-colors duration-200 text-left"
>
{prompt}
</button>
))}
</div>
{chatReady && !hasUserMessageInStage && !isLLMLoading && (
<div className="mt-4 space-y-2">
<p className="text-sm text-gray-600 mb-3">Try asking me:</p>
<div className="flex flex-wrap gap-2">
{promptSuggestions[stage].map((prompt, index) => (
<button
key={index}
onClick={() => handlePromptSelection(prompt)}
className="px-3 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded-lg border border-gray-300 transition-colors duration-200 text-left"
>
{prompt}
</button>
))}
</div>
)}
</div>
)}

{isLLMLoading && (
<div>
Expand Down
9 changes: 9 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
@tailwind components;
@tailwind utilities;

/* Chakra's preflight resets `font: inherit` on `*`, which as a side effect
wipes out the browser's native `em`/`i` italics. Restore it explicitly so
markdown-rendered emphasis (e.g. the chatbot's ReactMarkdown output)
actually renders italic. */
em,
i {
font-style: italic;
}

@layer components {
.btn-primary {
@apply bg-grey text-white w-full md:w-48 py-6 uppercase hover:opacity-70;
Expand Down