Skip to content

Commit 723ca71

Browse files
committed
feat(agent): improve action execution logging and enhance LLM response formatting #453
1 parent fe8c704 commit 723ca71

File tree

1 file changed

+59
-42
lines changed

1 file changed

+59
-42
lines changed

mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/CodingAgent.kt

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -145,26 +145,35 @@ class CodingAgent(
145145

146146
// 6. 执行所有行动
147147
if (actions.isEmpty()) {
148-
println("Agent completed reasoning")
148+
println("No actions needed\n")
149149
break
150150
}
151151

152-
for (action in actions) {
153-
// Debug: show parsed action
154-
if (action.type == "tool") {
155-
println("[DEBUG] Parsed tool: ${action.tool}, params: ${action.params}")
156-
}
157-
152+
for ((index, action) in actions.withIndex()) {
158153
// 执行行动
159154
val stepResult = executeAction(action)
160155
steps.add(stepResult)
161156

162-
println("Step result: ${if (stepResult.success) "" else ""} ${stepResult.action}")
157+
// Show compact result
158+
val icon = if (stepResult.success) "" else ""
159+
val toolName = action.tool ?: "unknown"
160+
print(" $icon $toolName")
161+
162+
// Show key result info if available
163+
if (stepResult.success && stepResult.result != null) {
164+
val preview = stepResult.result!!.take(60)
165+
if (preview.isNotEmpty() && !preview.startsWith("Successfully")) {
166+
print("${preview.replace("\n", " ")}")
167+
if (stepResult.result!!.length > 60) print("...")
168+
}
169+
}
170+
println()
163171
}
172+
println()
164173

165174
// 7. 检查是否完成
166175
if (isTaskComplete(llmResponse)) {
167-
println("✓ Task marked as complete")
176+
println("✓ Task marked as complete\n")
168177
break
169178
}
170179
}
@@ -537,18 +546,14 @@ class CodingAgent(
537546
success = false
538547
)
539548

540-
println("[DEBUG] Executing tool: $toolName with params: ${action.params}")
541-
542549
// Normalize parameters based on tool type
543550
val normalizedParams = normalizeToolParams(toolName, action.params)
544-
println("[DEBUG] Normalized params: $normalizedParams")
545551

546552
// 检查工具是否存在
547553
val tool = toolRegistry.getTool(toolName)
548554
if (tool == null) {
549555
val availableTools = toolRegistry.getToolNames().joinToString(", ")
550-
val errorMsg = "Tool not found: $toolName. Available tools: $availableTools"
551-
println("[DEBUG] $errorMsg")
556+
val errorMsg = "Tool not found: $toolName. Available: $availableTools"
552557
return AgentStep(
553558
step = currentIteration,
554559
action = toolName,
@@ -623,44 +628,56 @@ class CodingAgent(
623628
}
624629

625630
/**
626-
* Display LLM response with better formatting
631+
* Display LLM response with better formatting using CodeFence parser
627632
*/
628633
private fun displayLLMResponse(response: String) {
629-
println("\n[LLM Response] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
634+
println("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
630635

631-
// Extract reasoning text (before <devin> tags)
632-
val devinStart = response.indexOf("<devin>")
633-
val reasoningText = if (devinStart > 0) {
634-
response.substring(0, devinStart).trim()
635-
} else {
636-
response.trim()
637-
}
636+
// Parse all code fences (including devin blocks)
637+
val codeFences = cc.unitmesh.devins.parser.CodeFence.parseAll(response)
638638

639-
// Show reasoning (truncated if too long)
640-
if (reasoningText.isNotEmpty()) {
641-
val truncated = if (reasoningText.length > 300) {
642-
reasoningText.take(300) + "..."
643-
} else {
644-
reasoningText
639+
var hasDevinBlocks = false
640+
val reasoningParts = mutableListOf<String>()
641+
642+
for (fence in codeFences) {
643+
when (fence.languageId) {
644+
"devin" -> {
645+
hasDevinBlocks = true
646+
// Display tool call in a compact format
647+
val firstLine = fence.text.lines().first()
648+
println("🔧 $firstLine")
649+
}
650+
"markdown" -> {
651+
// Collect reasoning text
652+
reasoningParts.add(fence.text)
653+
}
645654
}
646-
println("💭 $truncated")
647655
}
648656

649-
// Extract and show tool calls
650-
val devinRegex = Regex("<devin>([\\s\\S]*?)</devin>", RegexOption.MULTILINE)
651-
val toolCalls = devinRegex.findAll(response).toList()
652-
653-
if (toolCalls.isNotEmpty()) {
654-
println("\n🔧 Tool Calls:")
655-
toolCalls.forEach { match ->
656-
val toolCode = match.groupValues[1].trim()
657-
// Show each tool call with proper formatting
658-
toolCode.lines().forEach { line ->
659-
if (line.trim().isNotEmpty()) {
660-
println(" $line")
657+
// Display reasoning at the top if we have tool calls
658+
if (hasDevinBlocks && reasoningParts.isNotEmpty()) {
659+
val reasoning = reasoningParts.joinToString(" ").trim()
660+
if (reasoning.isNotEmpty()) {
661+
// Show first sentence only
662+
val firstSentence = reasoning.split(Regex("[.!?]")).firstOrNull()?.trim() ?: ""
663+
if (firstSentence.isNotEmpty() && firstSentence.length > 10) {
664+
val display = if (firstSentence.length > 100) {
665+
firstSentence.take(100) + "..."
666+
} else {
667+
firstSentence
661668
}
669+
println("💭 $display")
662670
}
663671
}
672+
} else if (reasoningParts.isNotEmpty()) {
673+
// No tool calls, just show brief reasoning
674+
val reasoning = reasoningParts.joinToString(" ").trim()
675+
val preview = if (reasoning.length > 120) {
676+
reasoning.take(120) + "..."
677+
} else {
678+
reasoning
679+
}
680+
println("💭 $preview")
664681
}
665682

666683
println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n")

0 commit comments

Comments
 (0)