feat: 工具执行流式输出预览

- ToolEvent 新增 PROGRESS 阶段,工具可在执行中报告进度
- ToolContext 添加 progressCallback,工具可通过 reportProgress() 报告输出行
- BashTool 在读取每行输出时实时报告进度
- AgentLoop 在工具执行前设置进度回调,执行后清除
- ToolCallMsg 支持 outputLines 字段,保留最后 5 行流式预览
- 运行中的工具在消息区显示实时输出(灰色,截断至 120 字符)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
abel533
2026-04-04 19:22:35 +08:00
co-authored by Copilot
parent 012d5dfae6
commit 54c3cb41a9
6 changed files with 83 additions and 5 deletions
@@ -417,6 +417,16 @@ public class ClaudeCodeComponent extends Component<ClaudeCodeComponent.TuiState>
argSummary != null ? Text.of("(" + argSummary + ")").dimmed() : Text.of(""),
Text.of(" running...").dimmed()
));
// 流式输出预览(最后几行)
if (m.outputLines() != null && !m.outputLines().isEmpty()) {
for (String line : m.outputLines()) {
lines.add(Text.of(
Text.of("").dimmed(),
Text.of(line.length() > 120 ? line.substring(0, 117) + "..." : line)
.color(Color.BRIGHT_BLACK)
));
}
}
} else {
lines.add(Text.of(
Text.of("").color(Color.BRIGHT_GREEN),
@@ -1247,6 +1257,24 @@ public class ClaudeCodeComponent extends Component<ClaudeCodeComponent.TuiState>
}
}
/** 追加工具执行的流式输出行到最后一个运行中的 ToolCallMsg */
public void appendToolOutput(String line) {
synchronized (stateLock) {
TuiState s = getState();
List<UIMessage> msgs = new ArrayList<>(s.messages);
for (int i = msgs.size() - 1; i >= 0; i--) {
if (msgs.get(i) instanceof ToolCallMsg tcm && tcm.running()) {
msgs.set(i, tcm.appendOutput(line));
break;
}
}
setState(new TuiState(s.inputText, Collections.unmodifiableList(msgs),
s.scrollOffset, s.thinking, s.thinkingText));
}
}
/** 设置简单文本输入回调(用于无选项的 AskUser) */
public void requestTextInput(Consumer<String> callback) {
this.askOptions = null;