all: support hiding subconvo output
Some of it is systematically noisy.
diff --git a/claudetool/codereview/llm_review.go b/claudetool/codereview/llm_review.go
index 15205e7..32a8e00 100644
--- a/claudetool/codereview/llm_review.go
+++ b/claudetool/codereview/llm_review.go
@@ -32,6 +32,7 @@
info := conversation.ToolCallInfoFromContext(ctx)
convo := info.Convo.SubConvo()
convo.PromptCaching = false
+ convo.Hidden = true
convo.SystemPrompt = strings.TrimSpace(llmCodereviewPrompt)
initialMessage := llm.UserStringMessage("<diff>\n" + string(out) + "\n</diff>")
diff --git a/claudetool/pre-commit.go b/claudetool/pre-commit.go
index 306c7b9..f8fe5a0 100644
--- a/claudetool/pre-commit.go
+++ b/claudetool/pre-commit.go
@@ -55,6 +55,7 @@
info := conversation.ToolCallInfoFromContext(ctx)
sub := info.Convo.SubConvo()
+ sub.Hidden = true
sub.PromptCaching = false
sub.SystemPrompt = `Analyze the provided git commit messages to identify consistent patterns, including but not limited to:
diff --git a/llm/conversation/convo.go b/llm/conversation/convo.go
index 5a12256..7860a07 100644
--- a/llm/conversation/convo.go
+++ b/llm/conversation/convo.go
@@ -79,6 +79,9 @@
// The Conversation DOES NOT automatically enforce the budget.
// It is up to the caller to call OverBudget() as appropriate.
Budget Budget
+ // Hidden indicates that the output of this conversation should be hidden in the UI.
+ // This is useful for subconversations that can generate noisy, uninteresting output.
+ Hidden bool
// messages tracks the messages so far in the conversation.
messages []llm.Message
diff --git a/loop/agent.go b/loop/agent.go
index 0f08d36..95d7391 100644
--- a/loop/agent.go
+++ b/loop/agent.go
@@ -165,10 +165,14 @@
// Turn duration - the time taken for a complete agent turn
TurnDuration *time.Duration `json:"turnDuration,omitempty"`
+ // HideOutput indicates that this message should not be rendered in the UI.
+ // This is useful for subconversations that generate output that shouldn't be shown to the user.
+ HideOutput bool `json:"hide_output,omitempty"`
+
Idx int `json:"idx"`
}
-// SetConvo sets m.ConversationID and m.ParentConversationID based on convo.
+// SetConvo sets m.ConversationID, m.ParentConversationID, and m.HideOutput based on convo.
func (m *AgentMessage) SetConvo(convo *conversation.Convo) {
if convo == nil {
m.ConversationID = ""
@@ -176,6 +180,7 @@
return
}
m.ConversationID = convo.ID
+ m.HideOutput = convo.Hidden
if convo.Parent != nil {
m.ParentConversationID = &convo.Parent.ID
}
diff --git a/termui/termui.go b/termui/termui.go
index 1ffe655..7e4def9 100644
--- a/termui/termui.go
+++ b/termui/termui.go
@@ -150,6 +150,9 @@
if resp == nil {
return
}
+ if resp.HideOutput {
+ continue
+ }
// Typically a user message will start the thinking and a (top-level
// conversation) end of turn will stop it.
thinking := !(resp.EndOfTurn && resp.ParentConversationID == nil)
diff --git a/webui/src/types.ts b/webui/src/types.ts
index 9bc1e6d..78a73b0 100644
--- a/webui/src/types.ts
+++ b/webui/src/types.ts
@@ -45,6 +45,7 @@
end_time?: string | null;
elapsed?: Duration | null;
turnDuration?: Duration | null;
+ hide_output?: boolean;
idx: number;
}
diff --git a/webui/src/web-components/sketch-timeline-message.ts b/webui/src/web-components/sketch-timeline-message.ts
index b148203..f28b1a3 100644
--- a/webui/src/web-components/sketch-timeline-message.ts
+++ b/webui/src/web-components/sketch-timeline-message.ts
@@ -1090,11 +1090,11 @@
pointer-events: none;
transition: opacity 0.3s ease, transform 0.3s ease;
}
-
+
.floating-message.success {
background-color: rgba(40, 167, 69, 0.9);
}
-
+
.floating-message.error {
background-color: rgba(220, 53, 69, 0.9);
}
diff --git a/webui/src/web-components/sketch-timeline.ts b/webui/src/web-components/sketch-timeline.ts
index 7fbe83a..64f3db0 100644
--- a/webui/src/web-components/sketch-timeline.ts
+++ b/webui/src/web-components/sketch-timeline.ts
@@ -321,17 +321,33 @@
return html`
<div id="scroll-container">
<div class="timeline-container">
- ${repeat(this.messages, this.messageKey, (message, index) => {
- let previousMessage: AgentMessage;
- if (index > 0) {
- previousMessage = this.messages[index - 1];
- }
- return html`<sketch-timeline-message
- .message=${message}
- .previousMessage=${previousMessage}
- .open=${false}
- ></sketch-timeline-message>`;
- })}
+ ${repeat(
+ this.messages.filter((msg) => !msg.hide_output),
+ this.messageKey,
+ (message, index) => {
+ let previousMessageIndex =
+ this.messages.findIndex((m) => m === message) - 1;
+ let previousMessage =
+ previousMessageIndex >= 0
+ ? this.messages[previousMessageIndex]
+ : undefined;
+
+ // Skip hidden messages when determining previous message
+ while (previousMessage && previousMessage.hide_output) {
+ previousMessageIndex--;
+ previousMessage =
+ previousMessageIndex >= 0
+ ? this.messages[previousMessageIndex]
+ : undefined;
+ }
+
+ return html`<sketch-timeline-message
+ .message=${message}
+ .previousMessage=${previousMessage}
+ .open=${false}
+ ></sketch-timeline-message>`;
+ },
+ )}
${isThinking
? html`
<div class="thinking-indicator">