diff --git a/app/components/chat/Artifact.tsx b/app/components/chat/Artifact.tsx index 5f0c9910..230ed3c2 100644 --- a/app/components/chat/Artifact.tsx +++ b/app/components/chat/Artifact.tsx @@ -23,15 +23,16 @@ if (import.meta.hot) { interface ArtifactProps { messageId: string; + artifactId: string; } -export const Artifact = memo(({ messageId }: ArtifactProps) => { +export const Artifact = memo(({ artifactId }: ArtifactProps) => { const userToggledActions = useRef(false); const [showActions, setShowActions] = useState(false); const [allActionFinished, setAllActionFinished] = useState(false); const artifacts = useStore(workbenchStore.artifacts); - const artifact = artifacts[messageId]; + const artifact = artifacts[artifactId]; const actions = useStore( computed(artifact.runner.actions, (actions) => { diff --git a/app/components/chat/Markdown.tsx b/app/components/chat/Markdown.tsx index 90ba6b7f..bfc8a458 100644 --- a/app/components/chat/Markdown.tsx +++ b/app/components/chat/Markdown.tsx @@ -25,12 +25,17 @@ export const Markdown = memo(({ children, html = false, limitedMarkdown = false div: ({ className, children, node, ...props }) => { if (className?.includes('__boltArtifact__')) { const messageId = node?.properties.dataMessageId as string; + const artifactId = node?.properties.dataArtifactId as string; if (!messageId) { logger.error(`Invalid message id ${messageId}`); } - return ; + if (!artifactId) { + logger.error(`Invalid artifact id ${artifactId}`); + } + + return ; } if (className?.includes('__boltThought__')) { diff --git a/app/lib/runtime/message-parser.ts b/app/lib/runtime/message-parser.ts index 3b41b6d6..94017f20 100644 --- a/app/lib/runtime/message-parser.ts +++ b/app/lib/runtime/message-parser.ts @@ -12,6 +12,7 @@ const logger = createScopedLogger('MessageParser'); export interface ArtifactCallbackData extends BoltArtifactData { messageId: string; + artifactId: string; } export interface ActionCallbackData { @@ -34,6 +35,7 @@ export interface ParserCallbacks { interface ElementFactoryProps { messageId: string; + artifactId: string; } type ElementFactory = (props: ElementFactoryProps) => string; @@ -47,6 +49,7 @@ interface MessageState { position: number; insideArtifact: boolean; insideAction: boolean; + artifactCounter: number; currentArtifact?: BoltArtifactData; currentAction: BoltActionData; actionId: number; @@ -81,6 +84,7 @@ export class StreamingMessageParser { position: 0, insideAction: false, insideArtifact: false, + artifactCounter: 0, currentAction: { content: '' }, actionId: 0, }; @@ -187,7 +191,11 @@ export class StreamingMessageParser { break; } } else if (artifactCloseIndex !== -1) { - this._options.callbacks?.onArtifactClose?.({ messageId, ...currentArtifact }); + this._options.callbacks?.onArtifactClose?.({ + messageId, + artifactId: currentArtifact.id, + ...currentArtifact, + }); state.insideArtifact = false; state.currentArtifact = undefined; @@ -220,7 +228,9 @@ export class StreamingMessageParser { const artifactTitle = this.#extractAttribute(artifactTag, 'title') as string; const type = this.#extractAttribute(artifactTag, 'type') as string; - const artifactId = this.#extractAttribute(artifactTag, 'id') as string; + + // const artifactId = this.#extractAttribute(artifactTag, 'id') as string; + const artifactId = `${messageId}-${state.artifactCounter++}`; if (!artifactTitle) { logger.warn('Artifact title missing'); @@ -240,11 +250,15 @@ export class StreamingMessageParser { state.currentArtifact = currentArtifact; - this._options.callbacks?.onArtifactOpen?.({ messageId, ...currentArtifact }); + this._options.callbacks?.onArtifactOpen?.({ + messageId, + artifactId: currentArtifact.id, + ...currentArtifact, + }); const artifactFactory = this._options.artifactElement ?? createArtifactElement; - output += artifactFactory({ messageId }); + output += artifactFactory({ messageId, artifactId }); i = openTagEnd + 1; } else { diff --git a/app/lib/stores/workbench.ts b/app/lib/stores/workbench.ts index 4914ebc5..bd1572af 100644 --- a/app/lib/stores/workbench.ts +++ b/app/lib/stores/workbench.ts @@ -255,17 +255,17 @@ export class WorkbenchStore { } addArtifact({ messageId, title, id, type }: ArtifactCallbackData) { - const artifact = this.#getArtifact(messageId); + const artifact = this.#getArtifact(id); if (artifact) { return; } - if (!this.artifactIdList.includes(messageId)) { - this.artifactIdList.push(messageId); + if (!this.artifactIdList.includes(id)) { + this.artifactIdList.push(id); } - this.artifacts.setKey(messageId, { + this.artifacts.setKey(id, { id, title, closed: false, @@ -284,14 +284,14 @@ export class WorkbenchStore { }); } - updateArtifact({ messageId }: ArtifactCallbackData, state: Partial) { - const artifact = this.#getArtifact(messageId); + updateArtifact({ artifactId }: ArtifactCallbackData, state: Partial) { + const artifact = this.#getArtifact(artifactId); if (!artifact) { return; } - this.artifacts.setKey(messageId, { ...artifact, ...state }); + this.artifacts.setKey(artifactId, { ...artifact, ...state }); } addAction(data: ActionCallbackData) { // this._addAction(data); @@ -299,9 +299,9 @@ export class WorkbenchStore { this.addToExecutionQueue(() => this._addAction(data)); } async _addAction(data: ActionCallbackData) { - const { messageId } = data; + const { artifactId } = data; - const artifact = this.#getArtifact(messageId); + const artifact = this.#getArtifact(artifactId); if (!artifact) { unreachable('Artifact not found'); @@ -318,9 +318,9 @@ export class WorkbenchStore { } } async _runAction(data: ActionCallbackData, isStreaming: boolean = false) { - const { messageId } = data; + const { artifactId } = data; - const artifact = this.#getArtifact(messageId); + const artifact = this.#getArtifact(artifactId); if (!artifact) { unreachable('Artifact not found');