feat: starter_suggestions on AgentRef → "Try saying…" empty state

Lets the host app feed a small list of click-to-send prompts that the
dock shows above the empty composer on first chat. Solves the
"users don't know what to ask it" problem without baking the curation
into the lib — the app picks what to suggest (e.g. derived from the
agent's focus areas).

Changes:
- AgentRef gains optional starter_suggestions?: string[].
- Empty-bubbles render: when present, shows a "Try saying" header +
  bulleted list of clickable rows (capped at 4 — more makes the
  panel feel heavy). Click sends the prompt verbatim via the same
  sendMessage path as the composer.
- Falls back to the existing "Ask anything." line when none provided.
- Subtle hint "Click any to send — or write your own." nudges
  toward custom prompts.

Suggestions disappear naturally after the first message — the panel
only renders when bubbles is empty.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
jules
2026-06-07 20:15:40 +10:00
parent 777951ca9c
commit e4294fe896

View File

@@ -20,7 +20,18 @@ import { MessageBody } from "@crema/agent-ui"
/* Public types */ /* Public types */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
export type AgentRef = { id: string; name: string } export type AgentRef = {
id: string
name: string
/** Optional "try saying…" prompts shown to the user above the empty
* composer on first chat. Click sends the prompt verbatim. The dock
* doesn't curate or persist these — the host app decides what to
* suggest (e.g. derived from the agent's focus areas).
*
* Limit ~4 to keep the panel light; the dock won't truncate but
* more rows make the chat feel cluttered. */
starter_suggestions?: string[]
}
/** Structured page-awareness signal. Travels to the platform as its own /** Structured page-awareness signal. Travels to the platform as its own
* field — never concatenated into the user message — so page content * field — never concatenated into the user message — so page content
@@ -314,12 +325,43 @@ export function AgentDock({
{/* Messages */} {/* Messages */}
<div ref={scrollRef} className="flex-1 space-y-4 overflow-y-auto p-4"> <div ref={scrollRef} className="flex-1 space-y-4 overflow-y-auto p-4">
{bubbles.length === 0 ? ( {bubbles.length === 0 ? (
<div className="pt-8 text-center text-sm text-[var(--foreground)]/80"> <div className="space-y-4 pt-6">
{agentId <p className="text-center text-sm text-[var(--foreground)]/80">
? "Ask anything. I can see what page you're on." {agentId
: agents && agents.length === 0 ? "Ask anything. I can see what page you're on."
? "No agents available yet." : agents && agents.length === 0
: "Loading…"} ? "No agents available yet."
: "Loading…"}
</p>
{agentId &&
currentAgent?.starter_suggestions &&
currentAgent.starter_suggestions.length > 0 ? (
<div className="space-y-2">
<p className="px-1 text-xs font-medium uppercase tracking-wide text-[var(--foreground)]/60">
Try saying
</p>
<ul className="space-y-1.5">
{currentAgent.starter_suggestions
.slice(0, 4)
.map((s) => (
<li key={s}>
<button
type="button"
onClick={() => void sendMessage(s)}
disabled={sending}
className="w-full rounded-lg border border-[var(--border)] bg-[var(--chat-assistant-bg)] px-3 py-2 text-left text-sm leading-snug text-[var(--chat-assistant-fg)] transition-colors hover:border-[var(--primary)] disabled:opacity-60"
data-action="assistant-dock-starter"
>
{s}
</button>
</li>
))}
</ul>
<p className="px-1 text-[11px] text-[var(--foreground)]/50">
Click any to send or write your own.
</p>
</div>
) : null}
</div> </div>
) : ( ) : (
bubbles.map((b, i) => bubbles.map((b, i) =>