diff --git a/app/components/chat/Artifact.tsx b/app/components/chat/Artifact.tsx index 682a4c7..3ca2508 100644 --- a/app/components/chat/Artifact.tsx +++ b/app/components/chat/Artifact.tsx @@ -28,6 +28,7 @@ interface ArtifactProps { export const Artifact = memo(({ messageId }: ArtifactProps) => { const userToggledActions = useRef(false); const [showActions, setShowActions] = useState(false); + const [allActionFinished, setAllActionFinished] = useState(false); const artifacts = useStore(workbenchStore.artifacts); const artifact = artifacts[messageId]; @@ -47,6 +48,11 @@ export const Artifact = memo(({ messageId }: ArtifactProps) => { if (actions.length && !showActions && !userToggledActions.current) { setShowActions(true); } + + if (actions.length !== 0) { + const finished = !actions.find((action) => action.status !== 'complete'); + setAllActionFinished(finished); + } }, [actions]); return ( @@ -59,6 +65,18 @@ export const Artifact = memo(({ messageId }: ArtifactProps) => { workbenchStore.showWorkbench.set(!showWorkbench); }} > + {artifact.type == 'bundled' && ( + <> +
+ {allActionFinished ? ( +
+ ) : ( +
+ )} +
+
+ + )}
{artifact?.title}
Click to open Workbench
@@ -66,7 +84,7 @@ export const Artifact = memo(({ messageId }: ArtifactProps) => {
- {actions.length && ( + {actions.length && artifact.type !== 'bundled' && ( {
- {showActions && actions.length > 0 && ( + {artifact.type !== 'bundled' && showActions && actions.length > 0 && ( { transition={{ duration: 0.15 }} >
+
diff --git a/app/components/chat/ImportFolderButton.tsx b/app/components/chat/ImportFolderButton.tsx index f5cc662..3da78c1 100644 --- a/app/components/chat/ImportFolderButton.tsx +++ b/app/components/chat/ImportFolderButton.tsx @@ -79,7 +79,7 @@ ${content} role: 'assistant', content: `I'll help you set up these files.${binaryFilesMessage} - + ${fileArtifacts.join('\n\n')} `, id: generateId(), diff --git a/app/lib/runtime/__snapshots__/message-parser.spec.ts.snap b/app/lib/runtime/__snapshots__/message-parser.spec.ts.snap index 1543770..4b60f10 100644 --- a/app/lib/runtime/__snapshots__/message-parser.spec.ts.snap +++ b/app/lib/runtime/__snapshots__/message-parser.spec.ts.snap @@ -29,6 +29,7 @@ exports[`StreamingMessageParser > valid artifacts with actions > should correctl "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -37,6 +38,7 @@ exports[`StreamingMessageParser > valid artifacts with actions > should correctl "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -96,6 +98,7 @@ exports[`StreamingMessageParser > valid artifacts with actions > should correctl "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -104,6 +107,7 @@ exports[`StreamingMessageParser > valid artifacts with actions > should correctl "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -112,6 +116,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -120,6 +125,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -128,6 +134,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": "bundled", } `; @@ -136,6 +143,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": "bundled", } `; @@ -144,6 +152,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -152,6 +161,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -160,6 +170,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -168,6 +179,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -176,6 +188,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -184,6 +197,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -192,6 +206,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -200,6 +215,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -208,6 +224,7 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; @@ -216,5 +233,6 @@ exports[`StreamingMessageParser > valid artifacts without actions > should corre "id": "artifact_1", "messageId": "message_1", "title": "Some title", + "type": undefined, } `; diff --git a/app/lib/runtime/message-parser.spec.ts b/app/lib/runtime/message-parser.spec.ts index 739604b..4c5ba47 100644 --- a/app/lib/runtime/message-parser.spec.ts +++ b/app/lib/runtime/message-parser.spec.ts @@ -59,7 +59,11 @@ describe('StreamingMessageParser', () => { }, ], [ - ['Some text before foo Some more text'], + [ + 'Some text before foo Some more text', + ], { output: 'Some text before Some more text', callbacks: { onArtifactOpen: 1, onArtifactClose: 1, onActionOpen: 0, onActionClose: 0 }, diff --git a/app/lib/runtime/message-parser.ts b/app/lib/runtime/message-parser.ts index 48f3f52..ab6b695 100644 --- a/app/lib/runtime/message-parser.ts +++ b/app/lib/runtime/message-parser.ts @@ -192,6 +192,7 @@ export class StreamingMessageParser { const artifactTag = input.slice(i, openTagEnd + 1); const artifactTitle = this.#extractAttribute(artifactTag, 'title') as string; + const type = this.#extractAttribute(artifactTag, 'type') as string; const artifactId = this.#extractAttribute(artifactTag, 'id') as string; if (!artifactTitle) { @@ -207,6 +208,7 @@ export class StreamingMessageParser { const currentArtifact = { id: artifactId, title: artifactTitle, + type, } satisfies BoltArtifactData; state.currentArtifact = currentArtifact; diff --git a/app/lib/stores/workbench.ts b/app/lib/stores/workbench.ts index 369b254..de3a11e 100644 --- a/app/lib/stores/workbench.ts +++ b/app/lib/stores/workbench.ts @@ -19,6 +19,7 @@ import { description } from '~/lib/persistence'; export interface ArtifactState { id: string; title: string; + type?: string; closed: boolean; runner: ActionRunner; } @@ -230,7 +231,7 @@ export class WorkbenchStore { // TODO: what do we wanna do and how do we wanna recover from this? } - addArtifact({ messageId, title, id }: ArtifactCallbackData) { + addArtifact({ messageId, title, id, type }: ArtifactCallbackData) { const artifact = this.#getArtifact(messageId); if (artifact) { @@ -245,6 +246,7 @@ export class WorkbenchStore { id, title, closed: false, + type, runner: new ActionRunner(webcontainer, () => this.boltTerminal), }); } diff --git a/app/types/artifact.ts b/app/types/artifact.ts index e35697a..3a1e6b9 100644 --- a/app/types/artifact.ts +++ b/app/types/artifact.ts @@ -1,4 +1,5 @@ export interface BoltArtifactData { id: string; title: string; + type?: string | undefined; }