Skip to content

Commit 2ca21c6

Browse files
committed
Eager tool streaming
1 parent 832e859 commit 2ca21c6

File tree

2 files changed

+62
-5
lines changed

2 files changed

+62
-5
lines changed

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/agent-group.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export function AgentGroup({
111111
toolName={item.data.toolName}
112112
displayTitle={item.data.displayTitle}
113113
status={item.data.status}
114+
streamingArgs={item.data.streamingArgs}
114115
/>
115116
) : (
116117
<span

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-item.tsx

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import { useMemo } from 'react'
12
import { PillsRing } from '@/components/emcn'
3+
import { FunctionExecute } from '@/lib/copilot/generated/tool-catalog-v1'
24
import type { ToolCallStatus } from '../../../../types'
35
import { getToolIcon } from '../../utils'
6+
import { ChatContent } from '../chat-content/chat-content'
47

58
function CircleCheck({ className }: { className?: string }) {
69
return (
@@ -54,19 +57,72 @@ function StatusIcon({ status, toolName }: { status: ToolCallStatus; toolName: st
5457
return <CircleCheck className='h-[15px] w-[15px] text-[var(--text-tertiary)]' />
5558
}
5659

60+
const LANG_ALIASES: Record<string, string> = {
61+
javascript: 'javascript',
62+
python: 'python',
63+
shell: 'bash',
64+
bash: 'bash',
65+
}
66+
67+
function extractFunctionExecutePreview(raw: string): { code: string; lang: string } | null {
68+
if (!raw) return null
69+
const langMatch = raw.match(/"language"\s*:\s*"(\w+)"/)
70+
const lang = langMatch ? (LANG_ALIASES[langMatch[1]] ?? langMatch[1]) : 'javascript'
71+
72+
const codeStart = raw.indexOf('"code"')
73+
if (codeStart === -1) return null
74+
const colonIdx = raw.indexOf(':', codeStart + 6)
75+
if (colonIdx === -1) return null
76+
const quoteIdx = raw.indexOf('"', colonIdx + 1)
77+
if (quoteIdx === -1) return null
78+
79+
let value = raw.slice(quoteIdx + 1)
80+
if (value.endsWith('"}') || value.endsWith('"\n}')) {
81+
value = value.replace(/"\s*\}?\s*$/, '')
82+
}
83+
if (value.endsWith('"')) {
84+
value = value.slice(0, -1)
85+
}
86+
87+
const code = value
88+
.replace(/\\n/g, '\n')
89+
.replace(/\\t/g, '\t')
90+
.replace(/\\"/g, '"')
91+
.replace(/\\\\/g, '\\')
92+
93+
return code.length > 0 ? { code, lang } : null
94+
}
95+
5796
interface ToolCallItemProps {
5897
toolName: string
5998
displayTitle: string
6099
status: ToolCallStatus
100+
streamingArgs?: string
61101
}
62102

63-
export function ToolCallItem({ toolName, displayTitle, status }: ToolCallItemProps) {
103+
export function ToolCallItem({ toolName, displayTitle, status, streamingArgs }: ToolCallItemProps) {
104+
const extracted = useMemo(() => {
105+
if (toolName !== FunctionExecute.id || !streamingArgs) return null
106+
return extractFunctionExecutePreview(streamingArgs)
107+
}, [toolName, streamingArgs])
108+
const markdown = useMemo(
109+
() => (extracted ? `\`\`\`${extracted.lang}\n${extracted.code}\n\`\`\`` : null),
110+
[extracted]
111+
)
112+
64113
return (
65-
<div className='flex items-center gap-[8px] pl-[24px]'>
66-
<div className='flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center'>
67-
<StatusIcon status={status} toolName={toolName} />
114+
<div className='flex flex-col pl-[24px]'>
115+
<div className='flex items-center gap-[8px]'>
116+
<div className='flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center'>
117+
<StatusIcon status={status} toolName={toolName} />
118+
</div>
119+
<span className='font-base text-[13px] text-[var(--text-secondary)]'>{displayTitle}</span>
68120
</div>
69-
<span className='font-base text-[13px] text-[var(--text-secondary)]'>{displayTitle}</span>
121+
{markdown && (
122+
<div className='ml-[24px] max-h-[300px] overflow-auto'>
123+
<ChatContent content={markdown} isStreaming={status === 'executing'} />
124+
</div>
125+
)}
70126
</div>
71127
)
72128
}

0 commit comments

Comments
 (0)