Skip to content

Commit 4770b01

Browse files
authored
Markdown reading mode (#1789)
1 parent 8fa66ba commit 4770b01

File tree

19 files changed

+4522
-12460
lines changed

19 files changed

+4522
-12460
lines changed

apps/gateway/src/routes/api/v3/projects/versions/documents/run/run.handler.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,9 @@ describe('POST /run', () => {
950950
usage: {},
951951
documentLogUuid: 'fake-uuid',
952952
providerLog: {
953-
messages: [{ role: MessageRole.assistant, content: 'Hello', toolCalls: [] }],
953+
messages: [
954+
{ role: MessageRole.assistant, content: 'Hello', toolCalls: [] },
955+
],
954956
},
955957
})
956958
const trace = createTelemetryTrace({})
@@ -1044,7 +1046,9 @@ describe('POST /run', () => {
10441046
usage: {},
10451047
documentLogUuid: 'fake-uuid',
10461048
providerLog: {
1047-
messages: [{ role: MessageRole.assistant, content: 'Hello', toolCalls: [] }],
1049+
messages: [
1050+
{ role: MessageRole.assistant, content: 'Hello', toolCalls: [] },
1051+
],
10481052
},
10491053
})
10501054
const trace = createTelemetryTrace({})

apps/gateway/src/routes/api/v3/projects/versions/documents/run/run.handler.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,8 @@ export const runHandler: AppRouteHandler<RunRoute> = async (c) => {
6464
'api-background-runs',
6565
).then((r) => r.unwrap())
6666

67-
const shouldRunInBackground = background !== undefined
68-
? background
69-
: backgroundRunsFeatureEnabled
67+
const shouldRunInBackground =
68+
background !== undefined ? background : backgroundRunsFeatureEnabled
7069

7170
if (shouldRunInBackground) {
7271
return await handleBackgroundRun({

apps/web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
"rate-limiter-flexible": "5.0.3",
7575
"react": "catalog:",
7676
"react-data-grid": "7.0.0-beta.51",
77+
"katex": "^0.16.23",
7778
"react-dom": "catalog:",
7879
"require-in-the-middle": "7.5.2",
7980
"stripe": "18.1.0",

apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/_components/DocumentEditor/Editor/V2Playground/Chat/Actions/index.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1+
import ReadingToggle from '$/components/ReadingToggle'
12
import { ClientOnly } from '@latitude-data/web-ui/atoms/ClientOnly'
2-
import { SwitchToggle } from '@latitude-data/web-ui/atoms/Switch'
3-
import { Text } from '@latitude-data/web-ui/atoms/Text'
43

54
export type ActionsState = {
65
expandParameters?: boolean
@@ -10,10 +9,9 @@ export type ActionsState = {
109
export default function Actions(state: ActionsState) {
1110
return (
1211
<ClientOnly className='flex flex-row gap-2 items-center'>
13-
<Text.H6M>Expand parameters</Text.H6M>
14-
<SwitchToggle
15-
checked={state.expandParameters ?? false}
16-
onCheckedChange={state.setExpandParameters ?? (() => {})}
12+
<ReadingToggle
13+
enabled={state.expandParameters}
14+
setEnabled={state.setExpandParameters}
1715
/>
1816
</ClientOnly>
1917
)

apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/runs/_components/RunPanel/index.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
import { RunErrorMessage } from '$/app/(private)/projects/[projectId]/versions/[commitUuid]/_components/RunErrorMessage'
44
import { DocumentLogAnnotation } from '$/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/(withTabs)/logs/_components/DocumentLogs/DocumentLogInfo/Annotation'
55
import Chat from '$/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/_components/DocumentEditor/Editor/V2Playground/Chat'
6+
import { useCurrentCommit } from '$/app/providers/CommitProvider'
7+
import { useCurrentProject } from '$/app/providers/ProjectProvider'
68
import { MessageList } from '$/components/ChatWrapper'
79
import { getEvaluationMetricSpecification } from '$/components/evaluations'
10+
import ReadingToggle from '$/components/ReadingToggle'
811
import { usePlaygroundChat } from '$/hooks/playgroundChat/usePlaygroundChat'
912
import { useOnce } from '$/hooks/useMount'
1013
import { ROUTES } from '$/services/routes'
@@ -23,15 +26,12 @@ import {
2326
import { buildConversation } from '@latitude-data/core/helpers'
2427
import { Button } from '@latitude-data/web-ui/atoms/Button'
2528
import { Icon } from '@latitude-data/web-ui/atoms/Icons'
26-
import { SwitchToggle } from '@latitude-data/web-ui/atoms/Switch'
2729
import { Text } from '@latitude-data/web-ui/atoms/Text'
2830
import {
2931
AppLocalStorage,
3032
useLocalStorage,
3133
} from '@latitude-data/web-ui/hooks/useLocalStorage'
3234
import { useToolContentMap } from '@latitude-data/web-ui/hooks/useToolContentMap'
33-
import { useCurrentCommit } from '$/app/providers/CommitProvider'
34-
import { useCurrentProject } from '$/app/providers/ProjectProvider'
3535
import Link from 'next/link'
3636
import { useCallback, useMemo } from 'react'
3737
import { RunPanelStats } from './Stats'
@@ -242,10 +242,9 @@ function CompletedRunPanel({
242242
<Text.H6M>Messages</Text.H6M>
243243
{sourceMapAvailable && (
244244
<div className='flex flex-row gap-2 items-center'>
245-
<Text.H6M>Expand parameters</Text.H6M>
246-
<SwitchToggle
247-
checked={expandParameters}
248-
onCheckedChange={setExpandParameters}
245+
<ReadingToggle
246+
enabled={expandParameters}
247+
setEnabled={setExpandParameters}
249248
/>
250249
</div>
251250
)}

apps/web/src/app/layout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { TooltipProvider } from '@latitude-data/web-ui/atoms/Tooltip'
77
import { THEMES } from '@latitude-data/web-ui/molecules/TrippleThemeToggle'
88
import { ThemeProvider } from '@latitude-data/web-ui/providers'
99
import '@latitude-data/web-ui/styles.css'
10+
import 'katex/dist/katex.min.css'
1011
import NextTopLoader from 'nextjs-toploader'
1112
import type { ReactNode } from 'react'
1213
import 'react-data-grid/lib/styles.css'

apps/web/src/components/ChatWrapper/Message/MessageItem.tsx

Lines changed: 0 additions & 44 deletions
This file was deleted.

apps/web/src/components/ChatWrapper/Message/index.tsx

Lines changed: 73 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { memo, ReactNode, useEffect, useMemo, useState } from 'react'
1+
import { memo, ReactNode, Ref, useEffect, useMemo, useState } from 'react'
22

33
import {
44
FileContent,
@@ -15,11 +15,13 @@ import { Button } from '@latitude-data/web-ui/atoms/Button'
1515
import { CodeBlock } from '@latitude-data/web-ui/atoms/CodeBlock'
1616
import { Icon, IconName } from '@latitude-data/web-ui/atoms/Icons'
1717
import { Image } from '@latitude-data/web-ui/atoms/Image'
18+
import { Markdown } from '@latitude-data/web-ui/atoms/Markdown'
1819
import { Skeleton } from '@latitude-data/web-ui/atoms/Skeleton'
1920
import { Text } from '@latitude-data/web-ui/atoms/Text'
2021
import { Tooltip } from '@latitude-data/web-ui/atoms/Tooltip'
2122
import { colors, font, TextColor } from '@latitude-data/web-ui/tokens'
2223
import { cn } from '@latitude-data/web-ui/utils'
24+
import type { Components } from 'react-markdown'
2325
import { roleToString, roleVariant } from '..'
2426
import { ToolCallContent } from './ToolCall'
2527

@@ -126,25 +128,23 @@ export function MessageItemContent({
126128
agentToolsMap?: AgentToolsMap
127129
toolContentMap?: Record<string, ToolContent>
128130
}) {
129-
if (collapsedMessage)
130-
return (
131-
<Content
132-
value='...'
133-
color='foregroundMuted'
134-
size={size}
135-
agentToolsMap={agentToolsMap}
136-
/>
137-
)
131+
if (collapsedMessage) {
132+
return <Content value='...' color='foregroundMuted' size={size} />
133+
}
138134

139-
if (typeof content === 'string')
135+
if (typeof content === 'string') {
140136
return (
141137
<Content
142138
value={content}
143139
color='foregroundMuted'
144140
size={size}
141+
parameters={parameters}
142+
collapseParameters={collapseParameters}
145143
agentToolsMap={agentToolsMap}
144+
toolContentMap={toolContentMap}
146145
/>
147146
)
147+
}
148148

149149
return content.map((c, idx) => (
150150
<Content
@@ -202,17 +202,12 @@ const Content = ({
202202
}) => {
203203
if (typeof value === 'string') {
204204
try {
205-
const parsedValue = JSON.parse(value)
206-
return (
207-
<div key={`${index}`} className='py-2 max-w-full'>
208-
<div className='overflow-hidden rounded-xl w-full'>
209-
<CodeBlock language='json'>
210-
{JSON.stringify(parsedValue, null, 2)}
211-
</CodeBlock>
212-
</div>
213-
</div>
214-
)
205+
return <ContentJson json={JSON.parse(value)} />
215206
} catch (_) {
207+
if (!collapseParameters && value) {
208+
return <ContentMarkdown markdown={value} />
209+
}
210+
216211
return (
217212
<ContentText
218213
index={index}
@@ -229,17 +224,12 @@ const Content = ({
229224

230225
if (value.type === 'text') {
231226
try {
232-
const parsedValue = JSON.parse(value.text || '')
233-
return (
234-
<div key={`${index}`} className='py-2 max-w-full'>
235-
<div className='overflow-hidden rounded-xl w-full'>
236-
<CodeBlock language='json'>
237-
{JSON.stringify(parsedValue, null, 2)}
238-
</CodeBlock>
239-
</div>
240-
</div>
241-
)
227+
return <ContentJson json={JSON.parse(value.text || '')} />
242228
} catch (_) {
229+
if (!collapseParameters && value.text) {
230+
return <ContentMarkdown markdown={value.text} />
231+
}
232+
243233
return (
244234
<ContentText
245235
index={index}
@@ -297,6 +287,58 @@ const Content = ({
297287
}
298288
}
299289

290+
const ContentJson = memo(({ json }: { json: unknown }) => {
291+
return (
292+
<div className='py-2 max-w-full'>
293+
<div className='overflow-hidden rounded-xl w-full'>
294+
<CodeBlock language='json'>{JSON.stringify(json, null, 2)}</CodeBlock>
295+
</div>
296+
</div>
297+
)
298+
})
299+
300+
function isCodeBlockInline(children: string, className?: string) {
301+
return className === undefined && !children.includes('\n')
302+
}
303+
304+
function getLanguageFromCodeBlock(className?: string) {
305+
if (!className) return 'plaintext'
306+
return className.replace('language-', '')
307+
}
308+
309+
const ContentMarkdownComponents: Components = {
310+
// @ts-ignore: react-markdown passes an `inline` prop even though it’s not on HTMLElement attributes
311+
code: ({ inline, className, children, ...props }) => {
312+
const content = String(children)
313+
if (inline || isCodeBlockInline(content, className)) {
314+
const { ref, ...restProps } = props
315+
return (
316+
<div
317+
{...restProps}
318+
ref={ref as Ref<HTMLDivElement>}
319+
className='bg-muted rounded-md px-1 py-0.5 inline-flex flex-wrap'
320+
>
321+
<Text.H6M color='foregroundMuted'>{content}</Text.H6M>
322+
</div>
323+
)
324+
}
325+
326+
return (
327+
<CodeBlock
328+
{...props}
329+
language={getLanguageFromCodeBlock(className)}
330+
textWrap
331+
>
332+
{content}
333+
</CodeBlock>
334+
)
335+
},
336+
}
337+
338+
const ContentMarkdown = memo(({ markdown }: { markdown: string }) => {
339+
return <Markdown components={ContentMarkdownComponents}>{markdown}</Markdown>
340+
})
341+
300342
const ContentReasoning = memo(({ reasoning }: { reasoning?: string }) => {
301343
return (
302344
<div className='flex flex-col gap-4'>

apps/web/src/components/DocumentLogMessages/index.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import { useMemo } from 'react'
2-
1+
import { MessageList } from '$/components/ChatWrapper'
2+
import ReadingToggle from '$/components/ReadingToggle'
33
import { Message } from '@latitude-data/constants/legacyCompiler'
4-
import { SwitchToggle } from '@latitude-data/web-ui/atoms/Switch'
54
import { Text } from '@latitude-data/web-ui/atoms/Text'
65
import {
76
AppLocalStorage,
87
useLocalStorage,
98
} from '@latitude-data/web-ui/hooks/useLocalStorage'
10-
import { MessageList } from '$/components/ChatWrapper'
119
import { useToolContentMap } from '@latitude-data/web-ui/hooks/useToolContentMap'
10+
import { useMemo } from 'react'
1211

1312
export function DocumentLogMessages({
1413
documentLogParameters,
@@ -47,10 +46,9 @@ export function DocumentLogMessages({
4746
<Text.H6M>Messages</Text.H6M>
4847
{sourceMapAvailable && (
4948
<div className='flex flex-row gap-2 items-center'>
50-
<Text.H6M>Expand parameters</Text.H6M>
51-
<SwitchToggle
52-
checked={expandParameters}
53-
onCheckedChange={setExpandParameters}
49+
<ReadingToggle
50+
enabled={expandParameters}
51+
setEnabled={setExpandParameters}
5452
/>
5553
</div>
5654
)}

apps/web/src/components/PlaygroundCommon/Actions/index.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1+
import ReadingToggle from '$/components/ReadingToggle'
12
import { ClientOnly } from '@latitude-data/web-ui/atoms/ClientOnly'
2-
import { SwitchToggle } from '@latitude-data/web-ui/atoms/Switch'
3-
import { Text } from '@latitude-data/web-ui/atoms/Text'
43

54
export type ActionsState = {
65
expandParameters: boolean
@@ -10,10 +9,9 @@ export type ActionsState = {
109
export default function Actions(state: ActionsState) {
1110
return (
1211
<ClientOnly className='flex flex-row gap-2 items-center'>
13-
<Text.H6M>Expand parameters</Text.H6M>
14-
<SwitchToggle
15-
checked={state.expandParameters}
16-
onCheckedChange={state.setExpandParameters}
12+
<ReadingToggle
13+
enabled={state.expandParameters}
14+
setEnabled={state.setExpandParameters}
1715
/>
1816
</ClientOnly>
1917
)

0 commit comments

Comments
 (0)