frontmatter in skills/t/p

This commit is contained in:
2026-02-17 22:36:54 +00:00
parent cb603e3cf9
commit d3f94e45ea
19 changed files with 46 additions and 36 deletions
@@ -19,6 +19,7 @@ type EmbeddableChatProps = {
onBeforeSend?: (text: string) => boolean | Promise<boolean>;
commandFeedback?: string | null;
defaultInput?: string;
promptPrefix?: string;
className?: string;
cwd?: { root?: string; path: string };
autoSend?: boolean;
@@ -32,6 +33,7 @@ export const EmbeddableChat = ({
onBeforeSend,
commandFeedback = null,
defaultInput = '',
promptPrefix,
className,
cwd,
autoSend = false,
@@ -126,8 +128,8 @@ export const EmbeddableChat = ({
}
}
// Prepend attachment content to the prompt
let prompt = text;
// Prepend metadata/attachment content to the prompt
let prompt = promptPrefix ? `${promptPrefix}\n\n${text}` : text;
const ids: string[] = [];
const images: { filename: string; dataUrl: string }[] = [];
for (const a of attachments) {
@@ -55,11 +55,15 @@ const ResourceChat = ({
}: ResourceChatProps) => {
const client = useClient();
const claudeModels = useVisibleClaudeModels();
const seedFile = `${kind.toUpperCase()}.md`;
const promptFrontmatter = chatSessionId
? undefined
: `<frontmatter>\ninput file: ${filePath}\n${seedFile}: ${filePath}\ndir: ${resourceDir}\n\nBe aware of any extra files alongside the same dir as the ${kind} file we're handling, for possible extra context. You can also, if pertinent, create scripts or other files that will help you in the future.\n</frontmatter>`;
const defaultInput = chatSessionId
? undefined
: isNew
? `Help me create the content for this new ${kind} file: ${filePath}`
: `Help me understand and improve this ${kind} file: ${filePath}`;
? `Help me create the content for this new ${kind} file`
: `Help me understand and improve this ${kind} file`;
const storage = useMemo(
() => ({
@@ -99,6 +103,7 @@ const ResourceChat = ({
provider="claude"
availableModels={claudeModels}
defaultInput={defaultInput}
promptPrefix={promptFrontmatter}
className="h-full"
/>
);
+31 -20
View File
@@ -5,6 +5,21 @@ import type { ChatMessage } from './types';
import { ToolActivity } from './ToolActivity';
import { QuestionActivity } from './QuestionActivity';
const FRONTMATTER_RE = /^<frontmatter>([\s\S]*?)<\/frontmatter>\s*/;
const CollapsibleBlock = ({ label, content }: { label: string; content: string }) => (
<div className="flex justify-center">
<details className="max-w-[85%] rounded-2xl bg-duck-dark/5 border border-duck-dark/10 px-4 py-2 text-sm">
<summary className="text-xs text-duck-dark/40 hover:text-duck-dark/60 cursor-pointer select-none">
{label}
</summary>
<div className="mt-1.5 text-xs text-duck-dark/40 whitespace-pre-wrap border-l-2 border-duck-dark/10 pl-2 max-h-48 overflow-y-auto">
{content}
</div>
</details>
</div>
);
type MessageBubbleProps = {
message: ChatMessage;
onAnswer?: (text: string) => void;
@@ -12,31 +27,27 @@ type MessageBubbleProps = {
export const MessageBubble = ({ message, onAnswer }: MessageBubbleProps) => {
switch (message.role) {
case 'user':
case 'user': {
const match = message.text.match(FRONTMATTER_RE);
const metadata = match ? match[1]!.trim() : null;
const text = match ? message.text.slice(match[0]!.length) : message.text;
return (
<div className="flex justify-end">
<div className="max-w-[80%] rounded-2xl rounded-tr-sm bg-duck-yellow/10 border border-duck-yellow/20 px-4 py-2.5 text-sm text-duck-dark">
{message.images?.map((img, i) => (
<img key={i} src={img.dataUrl} alt={img.filename} className="max-w-full max-h-64 rounded-lg mb-2" />
))}
<div className="whitespace-pre-wrap">{message.text}</div>
<>
{metadata && <CollapsibleBlock label="Frontmatter" content={metadata} />}
<div className="flex justify-end">
<div className="max-w-[80%] rounded-2xl rounded-tr-sm bg-duck-yellow/10 border border-duck-yellow/20 px-4 py-2.5 text-sm text-duck-dark">
{message.images?.map((img, i) => (
<img key={i} src={img.dataUrl} alt={img.filename} className="max-w-full max-h-64 rounded-lg mb-2" />
))}
<div className="whitespace-pre-wrap">{text}</div>
</div>
</div>
</div>
</>
);
}
case 'system':
return (
<div className="flex justify-center">
<details className="max-w-[85%] rounded-2xl bg-duck-dark/5 border border-duck-dark/10 px-4 py-2 text-sm">
<summary className="text-xs text-duck-dark/40 hover:text-duck-dark/60 cursor-pointer select-none">
System prompt
</summary>
<div className="mt-1.5 text-xs text-duck-dark/40 whitespace-pre-wrap border-l-2 border-duck-dark/10 pl-2 max-h-48 overflow-y-auto">
{message.text}
</div>
</details>
</div>
);
return <CollapsibleBlock label="System prompt" content={message.text} />;
case 'assistant':
if (!message.text) return null;