mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 17:00:15 +01:00
* refactor: expand container * chore: bump @codesandbox/sandpack-react to latest * WIP: first pass, show editor * feat: implement ArtifactCodeEditor and ArtifactTabs components for enhanced artifact management * refactor: fileKey * refactor: auto scrolling code editor and add messageId to artifact * feat: first pass, editing artifact * feat: first pass, robust artifact replacement * fix: robust artifact replacement & re-render when expected * feat: Download Artifacts * refactor: improve artifact editing UX * fix: layout shift of new download button * fix: enhance missing output checks and logging in StreamRunManager
81 lines
2.5 KiB
JavaScript
81 lines
2.5 KiB
JavaScript
const ARTIFACT_START = ':::artifact';
|
|
const ARTIFACT_END = ':::';
|
|
|
|
/**
|
|
* Find all artifact boundaries in the message
|
|
* @param {TMessage} message
|
|
* @returns {Array<{start: number, end: number, source: 'content'|'text', partIndex?: number}>}
|
|
*/
|
|
const findAllArtifacts = (message) => {
|
|
const artifacts = [];
|
|
|
|
// Check content parts first
|
|
if (message.content?.length) {
|
|
message.content.forEach((part, partIndex) => {
|
|
if (part.type === 'text' && typeof part.text === 'string') {
|
|
let currentIndex = 0;
|
|
let start = part.text.indexOf(ARTIFACT_START, currentIndex);
|
|
|
|
while (start !== -1) {
|
|
const end = part.text.indexOf(ARTIFACT_END, start + ARTIFACT_START.length);
|
|
artifacts.push({
|
|
start,
|
|
end: end !== -1 ? end + ARTIFACT_END.length : part.text.length,
|
|
source: 'content',
|
|
partIndex,
|
|
text: part.text,
|
|
});
|
|
|
|
currentIndex = end !== -1 ? end + ARTIFACT_END.length : part.text.length;
|
|
start = part.text.indexOf(ARTIFACT_START, currentIndex);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Check message.text if no content parts
|
|
if (!artifacts.length && message.text) {
|
|
let currentIndex = 0;
|
|
let start = message.text.indexOf(ARTIFACT_START, currentIndex);
|
|
|
|
while (start !== -1) {
|
|
const end = message.text.indexOf(ARTIFACT_END, start + ARTIFACT_START.length);
|
|
artifacts.push({
|
|
start,
|
|
end: end !== -1 ? end + ARTIFACT_END.length : message.text.length,
|
|
source: 'text',
|
|
text: message.text,
|
|
});
|
|
|
|
currentIndex = end !== -1 ? end + ARTIFACT_END.length : message.text.length;
|
|
start = message.text.indexOf(ARTIFACT_START, currentIndex);
|
|
}
|
|
}
|
|
|
|
return artifacts;
|
|
};
|
|
|
|
const replaceArtifactContent = (originalText, artifact, original, updated) => {
|
|
const artifactContent = artifact.text.substring(artifact.start, artifact.end);
|
|
const relativeIndex = artifactContent.indexOf(original);
|
|
|
|
if (relativeIndex === -1) {
|
|
return null;
|
|
}
|
|
|
|
const absoluteIndex = artifact.start + relativeIndex;
|
|
const endText = originalText.substring(absoluteIndex + original.length);
|
|
const hasTrailingNewline = endText.startsWith('\n');
|
|
|
|
const updatedText =
|
|
originalText.substring(0, absoluteIndex) + updated + (hasTrailingNewline ? '' : '\n') + endText;
|
|
|
|
return updatedText.replace(/\n+(?=```\n:::)/g, '\n');
|
|
};
|
|
|
|
module.exports = {
|
|
ARTIFACT_START,
|
|
ARTIFACT_END,
|
|
findAllArtifacts,
|
|
replaceArtifactContent,
|
|
};
|