mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
Tools: render fragments
This commit is contained in:
@@ -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 (
|
||||
<Sheet color={props.color} variant={props.variant || 'soft'} sx={gridSx}>
|
||||
{props.data.map(({ label, value }, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div>{label}</div>
|
||||
<div>{value}</div>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
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: <strong>{part.invocation.name}</strong> },
|
||||
{ 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: <div style={{ whiteSpace: 'pre-wrap' }}>{part.invocation.code.trim()}</div>,
|
||||
},
|
||||
{ label: 'Id', value: part.id },
|
||||
];
|
||||
}
|
||||
}, [part]);
|
||||
|
||||
return (
|
||||
<BlocksContainer onDoubleClick={props.onDoubleClick}>
|
||||
<KeyValueGrid
|
||||
data={kvData}
|
||||
contentScaling={props.contentScaling}
|
||||
/>
|
||||
</BlocksContainer>
|
||||
);
|
||||
}
|
||||
@@ -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: <strong>{part.response.name}</strong> },
|
||||
{ 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 (
|
||||
<BlocksContainer onDoubleClick={props.onDoubleClick}>
|
||||
<KeyValueGrid
|
||||
data={kvData}
|
||||
contentScaling={props.contentScaling}
|
||||
color={part.error ? 'danger' : 'primary'}
|
||||
/>
|
||||
</BlocksContainer>
|
||||
);
|
||||
}
|
||||
@@ -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 (
|
||||
<BlocksContainer key={fId}>
|
||||
{part.invocation.type === 'function_call' ? (
|
||||
<Sheet color='neutral' variant='soft' sx={{
|
||||
flex: 1,
|
||||
border: '1px solid',
|
||||
borderColor: 'neutral.outlinedColor',
|
||||
width: '100%',
|
||||
borderRadius: 'lg',
|
||||
boxShadow: 'inset 2px 0 4px -2px rgba(0, 0, 0, 0.2)',
|
||||
fontSize: 'sm',
|
||||
p: 2,
|
||||
// grid layout with 2 cols
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'auto 1fr',
|
||||
columnGap: 2,
|
||||
rowGap: 1,
|
||||
}}>
|
||||
<div>Id</div>
|
||||
<div>{part.id}</div>
|
||||
<div>Name</div>
|
||||
<div>{part.invocation.name}</div>
|
||||
<div>Args</div>
|
||||
<div>{part.invocation.args/*?.replaceAll('{', '').replaceAll('}', '').replaceAll('","', '", "')*/}</div>
|
||||
</Sheet>
|
||||
) : (
|
||||
<Sheet color='neutral' variant='soft' sx={{
|
||||
flex: 1,
|
||||
border: '1px solid',
|
||||
borderColor: 'neutral.outlinedColor',
|
||||
width: '100%',
|
||||
borderRadius: 'lg',
|
||||
boxShadow: 'inset 2px 0 4px -2px rgba(0, 0, 0, 0.2)',
|
||||
fontSize: 'sm',
|
||||
p: 2,
|
||||
// grid layout with 2 cols
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'auto 1fr',
|
||||
columnGap: 2,
|
||||
rowGap: 1,
|
||||
}}>
|
||||
<div>Id</div>
|
||||
<div>{part.id}</div>
|
||||
<div>Language</div>
|
||||
<div>{part.invocation.language}</div>
|
||||
<div>Code</div>
|
||||
<div style={{ whiteSpace: 'pre' }}>{part.invocation.code?.trim()}</div>
|
||||
<div>Author</div>
|
||||
<div>{part.invocation.author}</div>
|
||||
</Sheet>
|
||||
)}
|
||||
</BlocksContainer>
|
||||
<BlockPartToolInvocation
|
||||
key={fId}
|
||||
toolInvocationPart={part}
|
||||
contentScaling={props.contentScaling}
|
||||
onDoubleClick={props.onDoubleClick}
|
||||
/>
|
||||
);
|
||||
|
||||
case 'tool_response':
|
||||
return (
|
||||
<BlocksContainer key={fId}>
|
||||
{part.response.type === 'function_call' ? (
|
||||
<Sheet color='neutral' variant='soft' sx={{
|
||||
flex: 1,
|
||||
border: '1px solid',
|
||||
borderColor: 'neutral.outlinedColor',
|
||||
width: '100%',
|
||||
borderRadius: 'lg',
|
||||
boxShadow: 'inset 2px 0 4px -2px rgba(0, 0, 0, 0.2)',
|
||||
fontSize: 'sm',
|
||||
p: 2,
|
||||
// grid layout with 2 cols
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'auto 1fr',
|
||||
columnGap: 2,
|
||||
rowGap: 1,
|
||||
}}>
|
||||
<div>Type</div>
|
||||
<div>Function Call Response</div>
|
||||
<div>Id</div>
|
||||
<div>{part.id}</div>
|
||||
<div>Error</div>
|
||||
<div>{part.error === null ? 'null' : part.error === 'false' ? '' : part.error}</div>
|
||||
<div>Name</div>
|
||||
<div style={{ fontWeight: 700 }}>{part.response.name}</div>
|
||||
<div>Result</div>
|
||||
<div style={{ fontWeight: 700 }}>{part.response.result}</div>
|
||||
<div>Environment</div>
|
||||
<div>{part.environment}</div>
|
||||
</Sheet>
|
||||
) : (
|
||||
<Sheet color='neutral' variant='solid' sx={{
|
||||
flex: 1,
|
||||
border: '1px solid',
|
||||
borderColor: 'neutral.outlinedColor',
|
||||
width: '100%',
|
||||
borderRadius: 'lg',
|
||||
boxShadow: 'inset 2px 0 4px -2px rgba(0, 0, 0, 0.2)',
|
||||
fontSize: 'sm',
|
||||
p: 2,
|
||||
// grid layout with 2 cols
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'auto 1fr',
|
||||
columnGap: 2,
|
||||
rowGap: 1,
|
||||
}}>
|
||||
<div>Type</div>
|
||||
<div>Code Execution Response</div>
|
||||
<div>Id</div>
|
||||
<div>{part.id}</div>
|
||||
<div>Error</div>
|
||||
<div>{part.error === null ? 'null' : part.error === 'false' ? '' : part.error}</div>
|
||||
<div>Result</div>
|
||||
<div style={{ fontWeight: 700 }}>{part.response.result}</div>
|
||||
<div>Executor</div>
|
||||
<div>{part.response.executor}</div>
|
||||
<div>Environment</div>
|
||||
<div>{part.environment}</div>
|
||||
</Sheet>
|
||||
)}
|
||||
</BlocksContainer>
|
||||
<BlockPartToolResponse
|
||||
key={fId}
|
||||
toolResponsePart={part}
|
||||
contentScaling={props.contentScaling}
|
||||
onDoubleClick={props.onDoubleClick}
|
||||
/>
|
||||
);
|
||||
|
||||
case '_pt_sentinel':
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user