Files
upstream-tldraw/templates/agent/client/components/chat-history/ChatHistoryGroupWithoutDiff.tsx
upstream-mirror a774ac673a
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
2026-09-23 16:12:52 +05:00

112 lines
3.2 KiB
TypeScript

import { useMemo, useState } from 'react'
import Markdown from 'react-markdown'
import { AgentIcon } from '../../../shared/icons/AgentIcon'
import { ChevronDownIcon } from '../../../shared/icons/ChevronDownIcon'
import { ChevronRightIcon } from '../../../shared/icons/ChevronRightIcon'
import { AgentAction } from '../../../shared/types/AgentAction'
import { ChatHistoryActionItem } from '../../../shared/types/ChatHistoryItem'
import { Streaming } from '../../../shared/types/Streaming'
import { useAgent } from '../../agent/TldrawAgentAppProvider'
import { ChatHistoryGroup } from './ChatHistoryGroup'
import { getActionInfo } from './getActionInfo'
export function ChatHistoryGroupWithoutDiff({ group }: { group: ChatHistoryGroup }) {
const agent = useAgent()
const { items } = group
const nonEmptyItems = useMemo(() => {
return items.filter((item) => {
const { description } = getActionInfo(item.action, agent)
return description !== null
})
}, [items, agent])
const [collapsed, setCollapsed] = useState(true)
const complete = useMemo(() => {
return items.every((item) => item.action.complete)
}, [items])
const summary = useMemo(() => {
const time = Math.floor(items.reduce((acc, item) => acc + item.action.time, 0) / 1000)
if (time === 0) return 'Thought for less than a second'
if (time === 1) return 'Thought for 1 second'
return `Thought for ${time} seconds`
}, [items])
if (nonEmptyItems.length === 0) {
return null
}
if (nonEmptyItems.length < 2) {
return (
<div className="chat-history-group">
{nonEmptyItems.map((item, i) => {
return <ChatHistoryItem item={item} key={'action-' + i} />
})}
</div>
)
}
const showContent = !collapsed || !complete
return (
<div className="chat-history-group">
{complete && (
<button onClick={() => setCollapsed((v) => !v)}>
<span>{showContent ? <ChevronDownIcon /> : <ChevronRightIcon />}</span>
{summary}
</button>
)}
{showContent && (
<div className="agent-actions-container">
{nonEmptyItems.map((item, i) => {
return <ChatHistoryItemExpanded action={item.action} key={'action-' + i} />
})}
</div>
)}
</div>
)
}
function ChatHistoryItem({ item }: { item: ChatHistoryActionItem }) {
const agent = useAgent()
const { action } = item
const { description, summary } = getActionInfo(action, agent)
const collapsible = summary !== null
const [collapsed, setCollapsed] = useState(collapsible)
if (!description) return null
return (
<div className="agent-actions-container">
{action.complete && collapsible && (
<button onClick={() => setCollapsed((v) => !v)}>
<span>{collapsed ? <ChevronRightIcon /> : <ChevronDownIcon />}</span>
{summary}
</button>
)}
{(!collapsed || !action.complete) && <ChatHistoryItemExpanded action={action} />}
</div>
)
}
function ChatHistoryItemExpanded({ action }: { action: Streaming<AgentAction> }) {
const agent = useAgent()
const { icon, description } = getActionInfo(action, agent)
return (
<div className={`agent-action agent-action-type-${action._type}`}>
{icon && (
<span>
<AgentIcon type={icon} />
</span>
)}
<span className="agent-action-description">
<Markdown>{description}</Markdown>
</span>
</div>
)
}