|
|
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 } |
|
|
| { id: string; description: string } |
|
|
| { documentId: string }; |
|
|
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); |
|
|
|