Skip to content

Commit 330eb61

Browse files
chore: track opentui submodule dirty state
🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
1 parent b030439 commit 330eb61

File tree

8 files changed

+422
-258
lines changed

8 files changed

+422
-258
lines changed

backend/src/tools/handlers/tool/spawn-agents.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,9 @@ export const handleSpawnAgents = ((params: {
125125
isOnlyChild: agents.length === 1,
126126
parentSystemPrompt,
127127
onResponseChunk: (chunk: string | PrintModeEvent) => {
128-
if (agents.length === 1) {
129-
writeToClient(chunk)
130-
}
131128
if (typeof chunk !== 'string') {
132129
return
133130
}
134-
// Send subagent streaming chunks to client
135131
sendSubagentChunk({
136132
userInputId,
137133
agentId: subAgentState.agentId,

cli/src/chat.tsx

Lines changed: 5 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
103103
},
104104
])
105105

106-
const completionCallbackRef = useRef<(() => void) | null>(null)
107106
const hasAutoSubmittedRef = useRef(false)
108107
const activeSubagentsRef = useRef<Set<string>>(new Set())
109108

@@ -167,70 +166,27 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
167166
setIsStreaming,
168167
setCanProcessQueue,
169168
abortControllerRef,
170-
completionCallbackRef,
171169
})
172170

173171
sendMessageRef.current = sendMessage
174172

175-
const hasStatus = useHasStatus(isWaitingForResponse, clipboardMessage)
176-
177173
useEffect(() => {
178174
if (initialPrompt && !hasAutoSubmittedRef.current) {
179175
hasAutoSubmittedRef.current = true
180176

181177
const timeout = setTimeout(() => {
182178
logger.info('Auto-submitting initial prompt', { prompt: initialPrompt })
183-
184-
const handleCompletion = () => {
185-
logger.info('Initial prompt completed, reading log file')
186-
187-
setTimeout(() => {
188-
if (renderer) {
189-
renderer.destroy()
190-
}
191-
192-
setTimeout(() => {
193-
try {
194-
const fs = require('fs')
195-
const path = require('path')
196-
const logPath = path.join(process.cwd(), 'debug', 'cli.log')
197-
198-
if (fs.existsSync(logPath)) {
199-
const logContents = fs.readFileSync(logPath, 'utf8')
200-
process.stdout.write('\n=== Debug Log Contents ===\n\n')
201-
process.stdout.write(logContents)
202-
process.stdout.write('\n\n=== End of Debug Log ===\n\n')
203-
} else {
204-
process.stdout.write(
205-
'Log file not found at: ' + logPath + '\n',
206-
)
207-
}
208-
} catch (error) {
209-
process.stdout.write(
210-
'Error reading log file: ' + String(error) + '\n',
211-
)
212-
}
213-
214-
process.exit(0)
215-
}, 100)
216-
}, 500)
179+
if (sendMessageRef.current) {
180+
sendMessageRef.current(initialPrompt)
217181
}
218-
219-
const timeoutId = setTimeout(() => {
220-
logger.warn('2-minute timeout reached, exiting')
221-
handleCompletion()
222-
}, 120000)
223-
224-
sendMessage(initialPrompt, () => {
225-
clearTimeout(timeoutId)
226-
handleCompletion()
227-
})
228182
}, 100)
229183

230184
return () => clearTimeout(timeout)
231185
}
232186
return undefined
233-
}, [initialPrompt, sendMessage])
187+
}, [initialPrompt])
188+
189+
const hasStatus = useHasStatus(isWaitingForResponse, clipboardMessage)
234190

235191
const handleSubmit = useCallback(() => {
236192
const trimmed = inputValue.trim()

cli/src/components/branch-item.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,7 @@ export const BranchItem = ({
8686
{finishedPreview}
8787
</text>
8888
)}
89-
{!isCollapsed && content && (
90-
<text wrap fg={theme.agentContentText}>
91-
{content}
92-
</text>
93-
)}
89+
{!isCollapsed && content && content}
9490
</box>
9591
</box>
9692
</box>

cli/src/components/message-block.tsx

Lines changed: 135 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ export const MessageBlock = ({
8282
: trimmedContent
8383
const prevBlock = idx > 0 ? blocks[idx - 1] : null
8484
const marginTop =
85-
prevBlock && (prevBlock.type === 'tool' || prevBlock.type === 'agent')
85+
prevBlock &&
86+
(prevBlock.type === 'tool' || prevBlock.type === 'agent')
8687
? 0
8788
: 0
8889
return (
@@ -107,7 +108,9 @@ export const MessageBlock = ({
107108
: ''
108109
const fullContent = inputContent + resultContent
109110

110-
const lines = fullContent.split('\n').filter((line) => line.trim())
111+
const lines = fullContent
112+
.split('\n')
113+
.filter((line) => line.trim())
111114
const firstLine = lines[0] || ''
112115
const lastLine = lines[lines.length - 1] || firstLine
113116

@@ -170,7 +173,12 @@ export const MessageBlock = ({
170173
const isCollapsed = collapsedAgents.has(block.agentId)
171174
const isStreaming = streamingAgents.has(block.agentId)
172175

173-
const lines = block.content
176+
const allTextContent =
177+
block.blocks
178+
?.filter((b) => b.type === 'text')
179+
.map((b) => (b as any).content)
180+
.join('') || ''
181+
const lines = allTextContent
174182
.split('\n')
175183
.filter((line) => line.trim())
176184
const firstLine = lines[0] || ''
@@ -195,88 +203,138 @@ export const MessageBlock = ({
195203
codeBlockWidth: agentCodeBlockWidth,
196204
palette: agentPalette,
197205
}
198-
199-
const displayContent = block.content
200-
? (hasMarkdown(block.content)
201-
? renderMarkdown(block.content, agentMarkdownOptions)
202-
: block.content)
203-
: ''
204-
205-
const nestedToolBlocks = block.blocks && block.blocks.length > 0 && !isCollapsed
206-
? block.blocks.map((nestedBlock, nestedIdx) => {
207-
if (nestedBlock.type === 'tool') {
208-
const displayInfo = getToolDisplayInfo(nestedBlock.toolName)
209-
const isNestedCollapsed = collapsedAgents.has(nestedBlock.toolCallId)
210-
const isNestedStreaming = streamingAgents.has(nestedBlock.toolCallId)
211206

212-
const inputContent = `\`\`\`json\n${JSON.stringify(nestedBlock.input, null, 2)}\n\`\`\``
213-
const codeBlockLang =
214-
nestedBlock.toolName === 'run_terminal_command' ? '' : 'yaml'
215-
const resultContent = nestedBlock.output
216-
? `\n\n**Result:**\n\`\`\`${codeBlockLang}\n${nestedBlock.output}\n\`\`\``
217-
: ''
218-
const fullNestedContent = inputContent + resultContent
207+
const displayContent = (
208+
<box style={{ flexDirection: 'column', gap: 0 }}>
209+
{block.blocks?.map((nestedBlock, nestedIdx) => {
210+
if (nestedBlock.type === 'text') {
211+
const renderedContent = hasMarkdown(nestedBlock.content)
212+
? renderStreamingMarkdown(
213+
nestedBlock.content,
214+
agentMarkdownOptions,
215+
)
216+
: nestedBlock.content
217+
return (
218+
<text
219+
key={`${messageId}-agent-${block.agentId}-text-${nestedIdx}`}
220+
wrap
221+
style={{ fg: theme.agentText, marginLeft: 2 }}
222+
>
223+
{renderedContent}
224+
</text>
225+
)
226+
}
227+
return null
228+
})}
229+
</box>
230+
)
231+
232+
const nestedToolBlocks =
233+
block.blocks && block.blocks.length > 0 && !isCollapsed
234+
? block.blocks.map((nestedBlock, nestedIdx) => {
235+
if (nestedBlock.type === 'tool') {
236+
const displayInfo = getToolDisplayInfo(
237+
nestedBlock.toolName,
238+
)
239+
const isNestedCollapsed = collapsedAgents.has(
240+
nestedBlock.toolCallId,
241+
)
242+
const isNestedStreaming = streamingAgents.has(
243+
nestedBlock.toolCallId,
244+
)
219245

220-
const nestedLines = fullNestedContent.split('\n').filter((line) => line.trim())
221-
const firstNestedLine = nestedLines[0] || ''
222-
const lastNestedLine = nestedLines[nestedLines.length - 1] || firstNestedLine
246+
const inputContent = `\`\`\`json\n${JSON.stringify(nestedBlock.input, null, 2)}\n\`\`\``
247+
const codeBlockLang =
248+
nestedBlock.toolName === 'run_terminal_command'
249+
? ''
250+
: 'yaml'
251+
const resultContent = nestedBlock.output
252+
? `\n\n**Result:**\n\`\`\`${codeBlockLang}\n${nestedBlock.output}\n\`\`\``
253+
: ''
254+
const fullNestedContent = inputContent + resultContent
223255

224-
const nestedStreamingPreview = isNestedStreaming
225-
? firstNestedLine.replace(/[#*_`~\[\]()]/g, '').trim() + '...'
226-
: ''
256+
const nestedLines = fullNestedContent
257+
.split('\n')
258+
.filter((line) => line.trim())
259+
const firstNestedLine = nestedLines[0] || ''
260+
const lastNestedLine =
261+
nestedLines[nestedLines.length - 1] || firstNestedLine
227262

228-
let nestedFinishedPreview = ''
229-
if (!isNestedStreaming && isNestedCollapsed) {
230-
if (nestedBlock.toolName === 'run_terminal_command' && nestedBlock.output) {
231-
const outputLines = nestedBlock.output
232-
.split('\n')
233-
.filter((line) => line.trim())
234-
const lastThreeLines = outputLines.slice(-3)
235-
const hasMoreLines = outputLines.length > 3
236-
nestedFinishedPreview = hasMoreLines
237-
? '...\n' + lastThreeLines.join('\n')
238-
: lastThreeLines.join('\n')
239-
} else {
240-
nestedFinishedPreview = lastNestedLine
241-
.replace(/[#*_`~\[\]()]/g, '')
242-
.trim()
263+
const nestedStreamingPreview = isNestedStreaming
264+
? firstNestedLine
265+
.replace(/[#*_`~\[\]()]/g, '')
266+
.trim() + '...'
267+
: ''
268+
269+
let nestedFinishedPreview = ''
270+
if (!isNestedStreaming && isNestedCollapsed) {
271+
if (
272+
nestedBlock.toolName === 'run_terminal_command' &&
273+
nestedBlock.output
274+
) {
275+
const outputLines = nestedBlock.output
276+
.split('\n')
277+
.filter((line) => line.trim())
278+
const lastThreeLines = outputLines.slice(-3)
279+
const hasMoreLines = outputLines.length > 3
280+
nestedFinishedPreview = hasMoreLines
281+
? '...\n' + lastThreeLines.join('\n')
282+
: lastThreeLines.join('\n')
283+
} else {
284+
nestedFinishedPreview = lastNestedLine
285+
.replace(/[#*_`~\[\]()]/g, '')
286+
.trim()
287+
}
243288
}
244-
}
245289

246-
const nestedDisplayContent = hasMarkdown(fullNestedContent)
247-
? renderMarkdown(fullNestedContent, agentMarkdownOptions)
248-
: fullNestedContent
290+
const nestedDisplayContent = hasMarkdown(
291+
fullNestedContent,
292+
)
293+
? renderMarkdown(
294+
fullNestedContent,
295+
agentMarkdownOptions,
296+
)
297+
: fullNestedContent
249298

250-
const nextNestedBlock = block.blocks![nestedIdx + 1]
251-
const isLastNestedBranch = !nextNestedBlock
252-
const nestedBranchChar = isLastNestedBranch ? ' └─ ' : ' ├─ '
299+
const nextNestedBlock = block.blocks![nestedIdx + 1]
300+
const isLastNestedBranch = !nextNestedBlock
301+
const nestedBranchChar = isLastNestedBranch
302+
? ' └─ '
303+
: ' ├─ '
253304

254-
return (
255-
<box key={`${messageId}-agent-${block.agentId}-tool-${nestedBlock.toolCallId}`}>
256-
<BranchItem
257-
name={displayInfo.name}
258-
content={nestedDisplayContent}
259-
isCollapsed={isNestedCollapsed}
260-
isStreaming={isNestedStreaming}
261-
branchChar={nestedBranchChar}
262-
streamingPreview={nestedStreamingPreview}
263-
finishedPreview={nestedFinishedPreview}
264-
theme={theme}
265-
onToggle={() => onToggleCollapsed(nestedBlock.toolCallId)}
266-
/>
267-
</box>
268-
)
269-
}
270-
return null
271-
})
272-
: null
305+
return (
306+
<box
307+
key={`${messageId}-agent-${block.agentId}-tool-${nestedBlock.toolCallId}`}
308+
>
309+
<BranchItem
310+
name={displayInfo.name}
311+
content={nestedDisplayContent}
312+
isCollapsed={isNestedCollapsed}
313+
isStreaming={isNestedStreaming}
314+
branchChar={nestedBranchChar}
315+
streamingPreview={nestedStreamingPreview}
316+
finishedPreview={nestedFinishedPreview}
317+
theme={theme}
318+
onToggle={() =>
319+
onToggleCollapsed(nestedBlock.toolCallId)
320+
}
321+
/>
322+
</box>
323+
)
324+
}
325+
return null
326+
})
327+
: null
273328

274329
const nextBlock = blocks[idx + 1]
275330
const isLastBranch = !nextBlock || nextBlock.type === 'text'
276331
const branchChar = isLastBranch ? '└─ ' : '├─ '
277332

278333
return (
279-
<box key={`${messageId}-agent-${block.agentId}`} style={{ flexDirection: 'column', gap: 0 }}>
334+
<box
335+
key={`${messageId}-agent-${block.agentId}`}
336+
style={{ flexDirection: 'column', gap: 0 }}
337+
>
280338
<BranchItem
281339
name={block.agentName}
282340
content={displayContent}
@@ -288,15 +346,19 @@ export const MessageBlock = ({
288346
theme={theme}
289347
onToggle={() => onToggleCollapsed(block.agentId)}
290348
/>
291-
{nestedToolBlocks}
349+
{isCollapsed ? null : nestedToolBlocks}
292350
</box>
293351
)
294352
}
295353
return null
296354
})}
297355
</box>
298356
) : (
299-
<text key={`message-content-${messageId}`} wrap style={{ fg: textColor }}>
357+
<text
358+
key={`message-content-${messageId}`}
359+
wrap
360+
style={{ fg: textColor }}
361+
>
300362
{isLoading
301363
? ''
302364
: hasMarkdown(content)

0 commit comments

Comments
 (0)