File size: 4,378 Bytes
867b17d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
import { memo } from 'react';
import type { ArtifactKind } from './artifact';
import { FileIcon, LoaderIcon, MessageIcon, PencilEditIcon } from './icons';
import { toast } from 'sonner';
import { useArtifact } from '@/hooks/use-artifact';
const getActionText = (
type: 'create' | 'update' | 'request-suggestions',
tense: 'present' | 'past',
) => {
switch (type) {
case 'create':
return tense === 'present' ? 'Creating' : 'Created';
case 'update':
return tense === 'present' ? 'Updating' : 'Updated';
case 'request-suggestions':
return tense === 'present'
? 'Adding suggestions'
: 'Added suggestions to';
default:
return null;
}
};
interface DocumentToolResultProps {
type: 'create' | 'update' | 'request-suggestions';
result: { id: string; title: string; kind: ArtifactKind };
isReadonly: boolean;
}
function PureDocumentToolResult({
type,
result,
isReadonly,
}: DocumentToolResultProps) {
const { setArtifact } = useArtifact();
return (
<button
type="button"
className="bg-background cursor-pointer border py-2 px-3 rounded-xl w-fit flex flex-row gap-3 items-start"
onClick={(event) => {
if (isReadonly) {
toast.error(
'Viewing files in shared chats is currently not supported.',
);
return;
}
const rect = event.currentTarget.getBoundingClientRect();
const boundingBox = {
top: rect.top,
left: rect.left,
width: rect.width,
height: rect.height,
};
setArtifact({
documentId: result.id,
kind: result.kind,
content: '',
title: result.title,
isVisible: true,
status: 'idle',
boundingBox,
});
}}
>
<div className="text-muted-foreground mt-1">
{type === 'create' ? (
<FileIcon />
) : type === 'update' ? (
<PencilEditIcon />
) : type === 'request-suggestions' ? (
<MessageIcon />
) : null}
</div>
<div className="text-left">
{`${getActionText(type, 'past')} "${result.title}"`}
</div>
</button>
);
}
export const DocumentToolResult = memo(PureDocumentToolResult, () => true);
interface DocumentToolCallProps {
type: 'create' | 'update' | 'request-suggestions';
args:
| { title: string; kind: ArtifactKind } // for create
| { id: string; description: string } // for update
| { documentId: string }; // for request-suggestions
isReadonly: boolean;
}
function PureDocumentToolCall({
type,
args,
isReadonly,
}: DocumentToolCallProps) {
const { setArtifact } = useArtifact();
return (
<button
type="button"
className="cursor pointer w-fit border py-2 px-3 rounded-xl flex flex-row items-start justify-between gap-3"
onClick={(event) => {
if (isReadonly) {
toast.error(
'Viewing files in shared chats is currently not supported.',
);
return;
}
const rect = event.currentTarget.getBoundingClientRect();
const boundingBox = {
top: rect.top,
left: rect.left,
width: rect.width,
height: rect.height,
};
setArtifact((currentArtifact) => ({
...currentArtifact,
isVisible: true,
boundingBox,
}));
}}
>
<div className="flex flex-row gap-3 items-start">
<div className="text-zinc-500 mt-1">
{type === 'create' ? (
<FileIcon />
) : type === 'update' ? (
<PencilEditIcon />
) : type === 'request-suggestions' ? (
<MessageIcon />
) : null}
</div>
<div className="text-left">
{`${getActionText(type, 'present')} ${
type === 'create' && 'title' in args && args.title
? `"${args.title}"`
: type === 'update' && 'description' in args
? `"${args.description}"`
: type === 'request-suggestions'
? 'for document'
: ''
}`}
</div>
</div>
<div className="animate-spin mt-1">{<LoaderIcon />}</div>
</button>
);
}
export const DocumentToolCall = memo(PureDocumentToolCall, () => true);
|