frontmatter in skills/t/p
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
|||||||
|
{"id":"8ce0e4ad-5739-42e6-9169-075b6deb2f3e"}
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
{"id":"44cc6c97-2a5e-4c39-86a7-121e4ecf2bab"}
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
{"id":"6abfee78-52e6-4d64-9641-5ad92f2995c3"}
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
{"id":"da96d8ac-cb9d-4d46-81b6-d2cfde733863"}
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
{"id":"36336dc9-e6e5-49c2-8a5b-a972001f95ce"}
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
|||||||
|
{"id":"a0d9fb2b-700f-4a79-a3d4-a175bad6d52a"}
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
{"id":"12f6c028-f2b8-4461-83cf-6ed8eb6bd3c9"}
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
{"id":"2dfd2db0-9f36-414b-8639-16918d98448c"}
|
|
||||||
@@ -19,6 +19,7 @@ type EmbeddableChatProps = {
|
|||||||
onBeforeSend?: (text: string) => boolean | Promise<boolean>;
|
onBeforeSend?: (text: string) => boolean | Promise<boolean>;
|
||||||
commandFeedback?: string | null;
|
commandFeedback?: string | null;
|
||||||
defaultInput?: string;
|
defaultInput?: string;
|
||||||
|
promptPrefix?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
cwd?: { root?: string; path: string };
|
cwd?: { root?: string; path: string };
|
||||||
autoSend?: boolean;
|
autoSend?: boolean;
|
||||||
@@ -32,6 +33,7 @@ export const EmbeddableChat = ({
|
|||||||
onBeforeSend,
|
onBeforeSend,
|
||||||
commandFeedback = null,
|
commandFeedback = null,
|
||||||
defaultInput = '',
|
defaultInput = '',
|
||||||
|
promptPrefix,
|
||||||
className,
|
className,
|
||||||
cwd,
|
cwd,
|
||||||
autoSend = false,
|
autoSend = false,
|
||||||
@@ -126,8 +128,8 @@ export const EmbeddableChat = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepend attachment content to the prompt
|
// Prepend metadata/attachment content to the prompt
|
||||||
let prompt = text;
|
let prompt = promptPrefix ? `${promptPrefix}\n\n${text}` : text;
|
||||||
const ids: string[] = [];
|
const ids: string[] = [];
|
||||||
const images: { filename: string; dataUrl: string }[] = [];
|
const images: { filename: string; dataUrl: string }[] = [];
|
||||||
for (const a of attachments) {
|
for (const a of attachments) {
|
||||||
|
|||||||
@@ -55,11 +55,15 @@ const ResourceChat = ({
|
|||||||
}: ResourceChatProps) => {
|
}: ResourceChatProps) => {
|
||||||
const client = useClient();
|
const client = useClient();
|
||||||
const claudeModels = useVisibleClaudeModels();
|
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
|
const defaultInput = chatSessionId
|
||||||
? undefined
|
? undefined
|
||||||
: isNew
|
: isNew
|
||||||
? `Help me create the content for this new ${kind} file: ${filePath}`
|
? `Help me create the content for this new ${kind} file`
|
||||||
: `Help me understand and improve this ${kind} file: ${filePath}`;
|
: `Help me understand and improve this ${kind} file`;
|
||||||
|
|
||||||
const storage = useMemo(
|
const storage = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@@ -99,6 +103,7 @@ const ResourceChat = ({
|
|||||||
provider="claude"
|
provider="claude"
|
||||||
availableModels={claudeModels}
|
availableModels={claudeModels}
|
||||||
defaultInput={defaultInput}
|
defaultInput={defaultInput}
|
||||||
|
promptPrefix={promptFrontmatter}
|
||||||
className="h-full"
|
className="h-full"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,21 @@ import type { ChatMessage } from './types';
|
|||||||
import { ToolActivity } from './ToolActivity';
|
import { ToolActivity } from './ToolActivity';
|
||||||
import { QuestionActivity } from './QuestionActivity';
|
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 = {
|
type MessageBubbleProps = {
|
||||||
message: ChatMessage;
|
message: ChatMessage;
|
||||||
onAnswer?: (text: string) => void;
|
onAnswer?: (text: string) => void;
|
||||||
@@ -12,31 +27,27 @@ type MessageBubbleProps = {
|
|||||||
|
|
||||||
export const MessageBubble = ({ message, onAnswer }: MessageBubbleProps) => {
|
export const MessageBubble = ({ message, onAnswer }: MessageBubbleProps) => {
|
||||||
switch (message.role) {
|
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 (
|
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">
|
{metadata && <CollapsibleBlock label="Frontmatter" content={metadata} />}
|
||||||
{message.images?.map((img, i) => (
|
<div className="flex justify-end">
|
||||||
<img key={i} src={img.dataUrl} alt={img.filename} className="max-w-full max-h-64 rounded-lg mb-2" />
|
<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) => (
|
||||||
<div className="whitespace-pre-wrap">{message.text}</div>
|
<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>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
case 'system':
|
case 'system':
|
||||||
return (
|
return <CollapsibleBlock label="System prompt" content={message.text} />;
|
||||||
<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>
|
|
||||||
);
|
|
||||||
|
|
||||||
case 'assistant':
|
case 'assistant':
|
||||||
if (!message.text) return null;
|
if (!message.text) return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user