From c3c65ea3d36ee2b3c6de5608da3060a568ae4579 Mon Sep 17 00:00:00 2001 From: Enrico Ros Date: Wed, 16 Oct 2024 16:55:21 -0700 Subject: [PATCH] Tools: render fragments --- .../BlockPartToolInvocation.tsx | 104 ++++++++++++++ .../BlockPartToolResponse.tsx | 49 +++++++ .../fragments-content/ContentFragments.tsx | 130 ++---------------- src/modules/blocks/blocks.styles.ts | 2 +- 4 files changed, 169 insertions(+), 116 deletions(-) create mode 100644 src/apps/chat/components/message/fragments-content/BlockPartToolInvocation.tsx create mode 100644 src/apps/chat/components/message/fragments-content/BlockPartToolResponse.tsx diff --git a/src/apps/chat/components/message/fragments-content/BlockPartToolInvocation.tsx b/src/apps/chat/components/message/fragments-content/BlockPartToolInvocation.tsx new file mode 100644 index 000000000..1ab7f279d --- /dev/null +++ b/src/apps/chat/components/message/fragments-content/BlockPartToolInvocation.tsx @@ -0,0 +1,104 @@ +import * as React from 'react'; + +import type { ColorPaletteProp, SxProps, VariantProp } from '@mui/joy/styles/types'; +import { Sheet } from '@mui/joy'; + +import { BlocksContainer } from '~/modules/blocks/BlocksContainers'; +import { useScaledTypographySx } from '~/modules/blocks/blocks.styles'; + +import type { ContentScaling } from '~/common/app.theme'; +import type { DMessageToolInvocationPart } from '~/common/stores/chat/chat.fragments'; + + +const keyValueGridSx = { + border: '1px solid', + borderRadius: 'sm', + boxShadow: 'inset 2px 0 4px -2px rgba(0, 0, 0, 0.2)', + p: 1.5, + + // Grid layout with 2 columns + display: 'grid', + gridTemplateColumns: 'auto 1fr', + // alignItems: 'baseline', + columnGap: 2, + rowGap: 0.5, + + // fade the text of the first column + // '& > :nth-of-type(odd)': { + // opacity: 0.67, + // // fontSize: '90%', + // }, +} as const; + + +export type KeyValueData = { label: string, value: React.ReactNode, asCode?: boolean }[]; + +export function KeyValueGrid(props: { + data: KeyValueData, + contentScaling: ContentScaling, + color?: ColorPaletteProp, + variant?: VariantProp, + stableSx?: SxProps, +}) { + + const { fontSize, lineHeight } = useScaledTypographySx(props.contentScaling, false, false); + + const gridSx = React.useMemo(() => ({ + ...keyValueGridSx, + // fontWeight, + fontSize, + lineHeight, + ...props.stableSx, + }), [fontSize, lineHeight, props.stableSx]); + + return ( + + {props.data.map(({ label, value }, index) => ( + +
{label}
+
{value}
+
+ ))} +
+ ); +} + + +export function BlockPartToolInvocation(props: { + toolInvocationPart: DMessageToolInvocationPart, + contentScaling: ContentScaling, + onDoubleClick?: (event: React.MouseEvent) => void; +}) { + + const part = props.toolInvocationPart; + + const kvData: KeyValueData = React.useMemo(() => { + switch (part.invocation.type) { + case 'function_call': + return [ + { label: 'Name', value: {part.invocation.name} }, + { label: 'Args', value: part.invocation.args || 'None', asCode: true }, + { label: 'Id', value: part.id }, + ]; + case 'code_execution': + return [ + { label: 'Language', value: part.invocation.language }, + { label: 'Author', value: part.invocation.author }, + { + label: 'Code', + value:
{part.invocation.code.trim()}
, + }, + { label: 'Id', value: part.id }, + ]; + } + }, [part]); + + return ( + + + + ); +} diff --git a/src/apps/chat/components/message/fragments-content/BlockPartToolResponse.tsx b/src/apps/chat/components/message/fragments-content/BlockPartToolResponse.tsx new file mode 100644 index 000000000..7d230c87f --- /dev/null +++ b/src/apps/chat/components/message/fragments-content/BlockPartToolResponse.tsx @@ -0,0 +1,49 @@ +import * as React from 'react'; + +import { BlocksContainer } from '~/modules/blocks/BlocksContainers'; + +import type { ContentScaling } from '~/common/app.theme'; +import type { DMessageToolResponsePart } from '~/common/stores/chat/chat.fragments'; + +import { KeyValueData, KeyValueGrid } from './BlockPartToolInvocation'; + + +export function BlockPartToolResponse(props: { + toolResponsePart: DMessageToolResponsePart, + contentScaling: ContentScaling, + onDoubleClick?: (event: React.MouseEvent) => void; +}) { + + const part = props.toolResponsePart; + + const kvData: KeyValueData = React.useMemo(() => { + switch (part.response.type) { + case 'function_call': + return [ + { label: 'Id', value: part.id }, + { label: 'Name', value: {part.response.name} }, + { label: 'Response', value: part.response.result, asCode: true }, + ...(!part.error ? [] : [{ label: 'Error', value: part.error }]), + { label: 'Environment', value: part.environment }, + ]; + case 'code_execution': + return [ + { label: 'Id', value: part.id }, + { label: 'Response', value: part.response.result, asCode: true }, + ...(!part.error ? [] : [{ label: 'Error', value: part.error }]), + { label: 'Executor', value: part.response.executor }, + { label: 'Environment', value: part.environment }, + ]; + } + }, [part]); + + return ( + + + + ); +} diff --git a/src/apps/chat/components/message/fragments-content/ContentFragments.tsx b/src/apps/chat/components/message/fragments-content/ContentFragments.tsx index aea6281c2..1592000ab 100644 --- a/src/apps/chat/components/message/fragments-content/ContentFragments.tsx +++ b/src/apps/chat/components/message/fragments-content/ContentFragments.tsx @@ -1,9 +1,7 @@ import * as React from 'react'; import type { SxProps } from '@mui/joy/styles/types'; -import { Box, Button, Sheet } from '@mui/joy'; - -import { BlocksContainer } from '~/modules/blocks/BlocksContainers'; +import { Box, Button } from '@mui/joy'; import { ScaledTextBlockRenderer } from '~/modules/blocks/ScaledTextBlockRenderer'; import type { ContentScaling, UIComplexityMode } from '~/common/app.theme'; @@ -17,6 +15,8 @@ import { BlockPartError } from './BlockPartError'; import { BlockPartImageRef } from './BlockPartImageRef'; import { BlockPartPlaceholder } from './BlockPartPlaceholder'; import { BlockPartText_AutoBlocks } from './BlockPartText_AutoBlocks'; +import { BlockPartToolInvocation } from './BlockPartToolInvocation'; +import { BlockPartToolResponse } from './BlockPartToolResponse'; const editLayoutSx: SxProps = { @@ -234,122 +234,22 @@ export function ContentFragments(props: { case 'tool_invocation': return ( - - {part.invocation.type === 'function_call' ? ( - -
Id
-
{part.id}
-
Name
-
{part.invocation.name}
-
Args
-
{part.invocation.args/*?.replaceAll('{', '').replaceAll('}', '').replaceAll('","', '", "')*/}
-
- ) : ( - -
Id
-
{part.id}
-
Language
-
{part.invocation.language}
-
Code
-
{part.invocation.code?.trim()}
-
Author
-
{part.invocation.author}
-
- )} -
+ ); case 'tool_response': return ( - - {part.response.type === 'function_call' ? ( - -
Type
-
Function Call Response
-
Id
-
{part.id}
-
Error
-
{part.error === null ? 'null' : part.error === 'false' ? '' : part.error}
-
Name
-
{part.response.name}
-
Result
-
{part.response.result}
-
Environment
-
{part.environment}
-
- ) : ( - -
Type
-
Code Execution Response
-
Id
-
{part.id}
-
Error
-
{part.error === null ? 'null' : part.error === 'false' ? '' : part.error}
-
Result
-
{part.response.result}
-
Executor
-
{part.response.executor}
-
Environment
-
{part.environment}
-
- )} -
+ ); case '_pt_sentinel': diff --git a/src/modules/blocks/blocks.styles.ts b/src/modules/blocks/blocks.styles.ts index 3cfa20176..e5d097876 100644 --- a/src/modules/blocks/blocks.styles.ts +++ b/src/modules/blocks/blocks.styles.ts @@ -41,7 +41,7 @@ export function useScaledImageSx(contentScaling: ContentScaling): SxProps { }), [contentScaling]); } -export function useScaledTypographySx(contentScaling: ContentScaling, showAsDanger: boolean, showAsItalic: boolean): SxProps { +export function useScaledTypographySx(contentScaling: ContentScaling, showAsDanger: boolean, showAsItalic: boolean) { return React.useMemo(() => ({ fontSize: themeScalingMap[contentScaling]?.blockFontSize ?? undefined, lineHeight: themeScalingMap[contentScaling]?.blockLineHeight ?? 1.75,