Skip to content

Instantly share code, notes, and snippets.

@mrwithersea
Last active October 2, 2025 16:02
Show Gist options
  • Select an option

  • Save mrwithersea/c04f6ad04e40708452879ed44a50e478 to your computer and use it in GitHub Desktop.

Select an option

Save mrwithersea/c04f6ad04e40708452879ed44a50e478 to your computer and use it in GitHub Desktop.
const ContextualSuggestions = () => {
const thread = useThread();
const [suggestions, setSuggestions] = useState<
Array<{ prompt: string; label: string }>
>([]);
useEffect(() => {
const generateContextualSuggestions = () => {
const messages = thread.messages;
const lastAssistantMessage = messages
.filter((m: { role: string }) => m.role === 'assistant')
.pop();
if (!lastAssistantMessage) return [];
// Extract the assistant's message text content
const messageText = lastAssistantMessage.content
.filter((part) => part.type === 'text')
.map((part) => part.text)
.join(' ');
const toolCalls =
lastAssistantMessage.content.filter(
(part) => part.type === 'tool-call'
) || [];
return toolCalls.flatMap((toolCall) => {
switch (toolCall.toolName) {
case 'suggest_contact':
const result = toolCall.result as {
structuredContent: {
suggestedContacts: { contactName: string }[];
};
};
if (!result) return [];
// Filter contacts to only include those mentioned in the assistant's message
const mentionedContacts =
result.structuredContent.suggestedContacts.filter((contact) =>
messageText.includes(contact.contactName)
);
return mentionedContacts.map((contact) => ({
prompt: contact.contactName,
label: contact.contactName,
}));
case 'suggest_contract_template':
const contractTemplateResult = toolCall.result as {
structuredContent: {
nextCursor: string;
templates: {
templateName: string;
templateId: string;
}[];
};
};
if (!contractTemplateResult) return [];
// Filter contract templates to only include those mentioned in the assistant's message
const mentionedTemplates =
contractTemplateResult.structuredContent.templates.filter(
(template) => messageText.includes(template.templateName)
);
return mentionedTemplates
? [
...mentionedTemplates.map((template) => ({
prompt: `${template.templateName} (${template.templateId})`,
label: template.templateName,
})),
...(contractTemplateResult.structuredContent.nextCursor
? [
{
prompt: 'Show more templates',
label: 'Show more',
},
]
: []),
]
: [];
default:
return [];
}
});
};
const newSuggestions = generateContextualSuggestions();
setSuggestions(newSuggestions);
}, [thread.messages]);
return (
<ThreadPrimitive.If running={false}>
{suggestions.length > 0 && (
<div className={styles.contextualSuggestions}>
{suggestions.map((suggestion, index) => (
<ThreadPrimitive.Suggestion
key={index}
asChild
prompt={suggestion.prompt}
method="replace"
autoSend
>
<ButtonTag IconPrefix={NewSmall}>{suggestion.label}</ButtonTag>
</ThreadPrimitive.Suggestion>
))}
</div>
)}
</ThreadPrimitive.If>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment