From f4987a4ecdf143ce51b6c29e93d4c529aa4af1e2 Mon Sep 17 00:00:00 2001 From: Dominic Elm Date: Mon, 22 Jul 2024 17:40:28 +0200 Subject: [PATCH] refactor: workbench store and move logic into action runner (#4) --- .../bolt/app/components/chat/Artifact.tsx | 114 +++++----- .../bolt/app/components/chat/Markdown.tsx | 9 +- .../bolt/app/components/workbench/Preview.tsx | 17 +- .../app/lib/.server/llm/switchable-stream.ts | 2 + .../bolt/app/lib/runtime/action-runner.ts | 195 ++++++++++++++---- .../app/lib/runtime/message-parser.spec.ts | 2 +- .../bolt/app/lib/runtime/message-parser.ts | 29 ++- packages/bolt/app/lib/stores/previews.ts | 7 + packages/bolt/app/lib/stores/workbench.ts | 147 ++----------- packages/bolt/app/routes/api.chat.ts | 10 +- 10 files changed, 295 insertions(+), 237 deletions(-) diff --git a/packages/bolt/app/components/chat/Artifact.tsx b/packages/bolt/app/components/chat/Artifact.tsx index 130b184..a321372 100644 --- a/packages/bolt/app/components/chat/Artifact.tsx +++ b/packages/bolt/app/components/chat/Artifact.tsx @@ -3,11 +3,11 @@ import { AnimatePresence, motion } from 'framer-motion'; import { computed } from 'nanostores'; import { memo, useEffect, useRef, useState } from 'react'; import { createHighlighter, type BundledLanguage, type BundledTheme, type HighlighterGeneric } from 'shiki'; +import type { ActionState } from '../../lib/runtime/action-runner'; import { chatStore } from '../../lib/stores/chat'; -import { getArtifactKey, workbenchStore, type ActionState } from '../../lib/stores/workbench'; +import { workbenchStore } from '../../lib/stores/workbench'; import { classNames } from '../../utils/classNames'; import { cubicEasingFn } from '../../utils/easings'; -import { IconButton } from '../ui/IconButton'; const highlighterOptions = { langs: ['shell'], @@ -22,20 +22,19 @@ if (import.meta.hot) { } interface ArtifactProps { - artifactId: string; messageId: string; } -export const Artifact = memo(({ artifactId, messageId }: ArtifactProps) => { +export const Artifact = memo(({ messageId }: ArtifactProps) => { const userToggledActions = useRef(false); const [showActions, setShowActions] = useState(false); const chat = useStore(chatStore); const artifacts = useStore(workbenchStore.artifacts); - const artifact = artifacts[getArtifactKey(artifactId, messageId)]; + const artifact = artifacts[messageId]; const actions = useStore( - computed(artifact.actions, (actions) => { + computed(artifact.runner.actions, (actions) => { return Object.values(actions); }), ); @@ -100,50 +99,7 @@ export const Artifact = memo(({ artifactId, messageId }: ArtifactProps) => { transition={{ duration: 0.15 }} >
- -

Actions

-
    - {actions.map((action, index) => { - const { status, type, content, abort } = action; - - return ( -
  • -
    -
    - {status === 'running' ? ( -
    - ) : status === 'pending' ? ( -
    - ) : status === 'complete' ? ( -
    - ) : status === 'failed' || status === 'aborted' ? ( -
    - ) : null} -
    - {type === 'file' ? ( -
    - Create {action.filePath} -
    - ) : type === 'shell' ? ( -
    - Run command - {abort !== undefined && status === 'running' && ( - abort()} /> - )} -
    - ) : null} -
    - {type === 'shell' && } -
  • - ); - })} -
-
+
)} @@ -188,3 +144,61 @@ function ShellCodeBlock({ classsName, code }: ShellCodeBlockProps) { > ); } + +interface ActionListProps { + actions: ActionState[]; +} + +const actionVariants = { + hidden: { opacity: 0, y: 20 }, + visible: { opacity: 1, y: 0 }, +}; + +const ActionList = memo(({ actions }: ActionListProps) => { + return ( + + + + ); +}); diff --git a/packages/bolt/app/components/chat/Markdown.tsx b/packages/bolt/app/components/chat/Markdown.tsx index a6e9c42..609e070 100644 --- a/packages/bolt/app/components/chat/Markdown.tsx +++ b/packages/bolt/app/components/chat/Markdown.tsx @@ -21,18 +21,13 @@ export const Markdown = memo(({ children }: MarkdownProps) => { return { div: ({ className, children, node, ...props }) => { if (className?.includes('__boltArtifact__')) { - const artifactId = node?.properties.dataArtifactId as string; const messageId = node?.properties.dataMessageId as string; - if (!artifactId) { - logger.debug(`Invalid artifact id ${messageId}`); - } - if (!messageId) { - logger.debug(`Invalid message id ${messageId}`); + logger.error(`Invalid message id ${messageId}`); } - return ; + return ; } return ( diff --git a/packages/bolt/app/components/workbench/Preview.tsx b/packages/bolt/app/components/workbench/Preview.tsx index 0b523c0..3a211f0 100644 --- a/packages/bolt/app/components/workbench/Preview.tsx +++ b/packages/bolt/app/components/workbench/Preview.tsx @@ -13,7 +13,14 @@ export const Preview = memo(() => { const [iframeUrl, setIframeUrl] = useState(); useEffect(() => { - if (activePreview && !iframeUrl) { + if (!activePreview) { + setUrl(''); + setIframeUrl(undefined); + + return; + } + + if (!iframeUrl) { const { baseUrl } = activePreview; setUrl(baseUrl); @@ -31,16 +38,16 @@ export const Preview = memo(() => {
-
+
Preview
-
+
-
+
{
{activePreview ? ( - +