2
0
Эх сурвалжийг харах

feat: toggle tool details visible

adamdotdevin 6 сар өмнө
parent
commit
5e777fd2a2

+ 1 - 0
packages/opencode/src/config/config.ts

@@ -202,6 +202,7 @@ export namespace Config {
       session_interrupt: z.string().optional().default("esc").describe("Interrupt current session"),
       session_interrupt: z.string().optional().default("esc").describe("Interrupt current session"),
       session_compact: z.string().optional().default("<leader>c").describe("Compact the session"),
       session_compact: z.string().optional().default("<leader>c").describe("Compact the session"),
       tool_details: z.string().optional().default("<leader>d").describe("Toggle tool details"),
       tool_details: z.string().optional().default("<leader>d").describe("Toggle tool details"),
+      thinking_blocks: z.string().optional().default("<leader>b").describe("Toggle thinking blocks"),
       model_list: z.string().optional().default("<leader>m").describe("List available models"),
       model_list: z.string().optional().default("<leader>m").describe("List available models"),
       theme_list: z.string().optional().default("<leader>t").describe("List available themes"),
       theme_list: z.string().optional().default("<leader>t").describe("List available themes"),
       file_list: z.string().optional().default("<leader>f").describe("List files"),
       file_list: z.string().optional().default("<leader>f").describe("List files"),

+ 1 - 3
packages/opencode/src/session/index.ts

@@ -1007,7 +1007,7 @@ export namespace Session {
       async process(stream: StreamTextResult<Record<string, AITool>, never>) {
       async process(stream: StreamTextResult<Record<string, AITool>, never>) {
         try {
         try {
           let currentText: MessageV2.TextPart | undefined
           let currentText: MessageV2.TextPart | undefined
-          // let reasoningMap: Record<string, MessageV2.ReasoningPart> = {}
+          let reasoningMap: Record<string, MessageV2.ReasoningPart> = {}
 
 
           for await (const value of stream.fullStream) {
           for await (const value of stream.fullStream) {
             log.info("part", {
             log.info("part", {
@@ -1017,7 +1017,6 @@ export namespace Session {
               case "start":
               case "start":
                 break
                 break
 
 
-              /*
               case "reasoning-start":
               case "reasoning-start":
                 if (value.id in reasoningMap) {
                 if (value.id in reasoningMap) {
                   continue
                   continue
@@ -1055,7 +1054,6 @@ export namespace Session {
                   delete reasoningMap[value.id]
                   delete reasoningMap[value.id]
                 }
                 }
                 break
                 break
-                */
 
 
               case "tool-input-start":
               case "tool-input-start":
                 const part = await updatePart({
                 const part = await updatePart({

+ 2 - 0
packages/tui/internal/app/state.go

@@ -32,6 +32,8 @@ type State struct {
 	MessagesRight      bool                  `toml:"messages_right"`
 	MessagesRight      bool                  `toml:"messages_right"`
 	SplitDiff          bool                  `toml:"split_diff"`
 	SplitDiff          bool                  `toml:"split_diff"`
 	MessageHistory     []Prompt              `toml:"message_history"`
 	MessageHistory     []Prompt              `toml:"message_history"`
+	ShowToolDetails    *bool                 `toml:"show_tool_details"`
+	ShowThinkingBlocks *bool                 `toml:"show_thinking_blocks"`
 }
 }
 
 
 func NewState() *State {
 func NewState() *State {

+ 7 - 0
packages/tui/internal/commands/command.go

@@ -119,6 +119,7 @@ const (
 	SessionCompactCommand       CommandName = "session_compact"
 	SessionCompactCommand       CommandName = "session_compact"
 	SessionExportCommand        CommandName = "session_export"
 	SessionExportCommand        CommandName = "session_export"
 	ToolDetailsCommand          CommandName = "tool_details"
 	ToolDetailsCommand          CommandName = "tool_details"
+	ThinkingBlocksCommand       CommandName = "thinking_blocks"
 	ModelListCommand            CommandName = "model_list"
 	ModelListCommand            CommandName = "model_list"
 	AgentListCommand            CommandName = "agent_list"
 	AgentListCommand            CommandName = "agent_list"
 	ModelCycleRecentCommand     CommandName = "model_cycle_recent"
 	ModelCycleRecentCommand     CommandName = "model_cycle_recent"
@@ -245,6 +246,12 @@ func LoadFromConfig(config *opencode.Config) CommandRegistry {
 			Keybindings: parseBindings("<leader>d"),
 			Keybindings: parseBindings("<leader>d"),
 			Trigger:     []string{"details"},
 			Trigger:     []string{"details"},
 		},
 		},
+		{
+			Name:        ThinkingBlocksCommand,
+			Description: "toggle thinking blocks",
+			Keybindings: parseBindings("<leader>b"),
+			Trigger:     []string{"thinking"},
+		},
 		{
 		{
 			Name:        ModelListCommand,
 			Name:        ModelListCommand,
 			Description: "list models",
 			Description: "list models",

+ 70 - 44
packages/tui/internal/components/chat/messages.go

@@ -33,6 +33,7 @@ type MessagesComponent interface {
 	HalfPageUp() (tea.Model, tea.Cmd)
 	HalfPageUp() (tea.Model, tea.Cmd)
 	HalfPageDown() (tea.Model, tea.Cmd)
 	HalfPageDown() (tea.Model, tea.Cmd)
 	ToolDetailsVisible() bool
 	ToolDetailsVisible() bool
+	ThinkingBlocksVisible() bool
 	GotoTop() (tea.Model, tea.Cmd)
 	GotoTop() (tea.Model, tea.Cmd)
 	GotoBottom() (tea.Model, tea.Cmd)
 	GotoBottom() (tea.Model, tea.Cmd)
 	CopyLastMessage() (tea.Model, tea.Cmd)
 	CopyLastMessage() (tea.Model, tea.Cmd)
@@ -41,20 +42,21 @@ type MessagesComponent interface {
 }
 }
 
 
 type messagesComponent struct {
 type messagesComponent struct {
-	width, height   int
-	app             *app.App
-	header          string
-	viewport        viewport.Model
-	clipboard       []string
-	cache           *PartCache
-	loading         bool
-	showToolDetails bool
-	rendering       bool
-	dirty           bool
-	tail            bool
-	partCount       int
-	lineCount       int
-	selection       *selection
+	width, height      int
+	app                *app.App
+	header             string
+	viewport           viewport.Model
+	clipboard          []string
+	cache              *PartCache
+	loading            bool
+	showToolDetails    bool
+	showThinkingBlocks bool
+	rendering          bool
+	dirty              bool
+	tail               bool
+	partCount          int
+	lineCount          int
+	selection          *selection
 }
 }
 
 
 type selection struct {
 type selection struct {
@@ -94,6 +96,7 @@ func (s selection) coords(offset int) *selection {
 }
 }
 
 
 type ToggleToolDetailsMsg struct{}
 type ToggleToolDetailsMsg struct{}
+type ToggleThinkingBlocksMsg struct{}
 
 
 func (m *messagesComponent) Init() tea.Cmd {
 func (m *messagesComponent) Init() tea.Cmd {
 	return tea.Batch(m.viewport.Init())
 	return tea.Batch(m.viewport.Init())
@@ -160,7 +163,12 @@ func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		return m, m.renderView()
 		return m, m.renderView()
 	case ToggleToolDetailsMsg:
 	case ToggleToolDetailsMsg:
 		m.showToolDetails = !m.showToolDetails
 		m.showToolDetails = !m.showToolDetails
-		return m, m.renderView()
+		m.app.State.ShowToolDetails = &m.showToolDetails
+		return m, tea.Batch(m.renderView(), m.app.SaveState())
+	case ToggleThinkingBlocksMsg:
+		m.showThinkingBlocks = !m.showThinkingBlocks
+		m.app.State.ShowThinkingBlocks = &m.showThinkingBlocks
+		return m, tea.Batch(m.renderView(), m.app.SaveState())
 	case app.SessionLoadedMsg, app.SessionClearedMsg:
 	case app.SessionLoadedMsg, app.SessionClearedMsg:
 		m.cache.Clear()
 		m.cache.Clear()
 		m.tail = true
 		m.tail = true
@@ -561,32 +569,34 @@ func (m *messagesComponent) renderView() tea.Cmd {
 						if reverted {
 						if reverted {
 							continue
 							continue
 						}
 						}
-						text := "..."
+						if !m.showThinkingBlocks {
+							continue
+						}
 						if part.Text != "" {
 						if part.Text != "" {
-							text = part.Text
+							text := part.Text
+							content = renderText(
+								m.app,
+								message.Info,
+								text,
+								casted.ModelID,
+								m.showToolDetails,
+								width,
+								"",
+								true,
+								[]opencode.FilePart{},
+								[]opencode.AgentPart{},
+							)
+							content = lipgloss.PlaceHorizontal(
+								m.width,
+								lipgloss.Center,
+								content,
+								styles.WhitespaceStyle(t.Background()),
+							)
+							partCount++
+							lineCount += lipgloss.Height(content) + 1
+							blocks = append(blocks, content)
+							hasContent = true
 						}
 						}
-						content = renderText(
-							m.app,
-							message.Info,
-							text,
-							casted.ModelID,
-							m.showToolDetails,
-							width,
-							"",
-							true,
-							[]opencode.FilePart{},
-							[]opencode.AgentPart{},
-						)
-						content = lipgloss.PlaceHorizontal(
-							m.width,
-							lipgloss.Center,
-							content,
-							styles.WhitespaceStyle(t.Background()),
-						)
-						partCount++
-						lineCount += lipgloss.Height(content) + 1
-						blocks = append(blocks, content)
-						hasContent = true
 					}
 					}
 				}
 				}
 
 
@@ -1006,6 +1016,10 @@ func (m *messagesComponent) ToolDetailsVisible() bool {
 	return m.showToolDetails
 	return m.showToolDetails
 }
 }
 
 
+func (m *messagesComponent) ThinkingBlocksVisible() bool {
+	return m.showThinkingBlocks
+}
+
 func (m *messagesComponent) GotoTop() (tea.Model, tea.Cmd) {
 func (m *messagesComponent) GotoTop() (tea.Model, tea.Cmd) {
 	m.viewport.GotoTop()
 	m.viewport.GotoTop()
 	return m, nil
 	return m, nil
@@ -1202,11 +1216,23 @@ func NewMessagesComponent(app *app.App) MessagesComponent {
 		vp.MouseWheelDelta = 4
 		vp.MouseWheelDelta = 4
 	}
 	}
 
 
+	// Default to showing tool details, hidden thinking blocks
+	showToolDetails := true
+	if app.State.ShowToolDetails != nil {
+		showToolDetails = *app.State.ShowToolDetails
+	}
+
+	showThinkingBlocks := false
+	if app.State.ShowThinkingBlocks != nil {
+		showThinkingBlocks = *app.State.ShowThinkingBlocks
+	}
+
 	return &messagesComponent{
 	return &messagesComponent{
-		app:             app,
-		viewport:        vp,
-		showToolDetails: true,
-		cache:           NewPartCache(),
-		tail:            true,
+		app:                app,
+		viewport:           vp,
+		showToolDetails:    showToolDetails,
+		showThinkingBlocks: showThinkingBlocks,
+		cache:              NewPartCache(),
+		tail:               true,
 	}
 	}
 }
 }

+ 7 - 0
packages/tui/internal/tui/tui.go

@@ -1142,6 +1142,13 @@ func (a Model) executeCommand(command commands.Command) (tea.Model, tea.Cmd) {
 		}
 		}
 		cmds = append(cmds, util.CmdHandler(chat.ToggleToolDetailsMsg{}))
 		cmds = append(cmds, util.CmdHandler(chat.ToggleToolDetailsMsg{}))
 		cmds = append(cmds, toast.NewInfoToast(message))
 		cmds = append(cmds, toast.NewInfoToast(message))
+	case commands.ThinkingBlocksCommand:
+		message := "Thinking blocks are now visible"
+		if a.messages.ThinkingBlocksVisible() {
+			message = "Thinking blocks are now hidden"
+		}
+		cmds = append(cmds, util.CmdHandler(chat.ToggleThinkingBlocksMsg{}))
+		cmds = append(cmds, toast.NewInfoToast(message))
 	case commands.ModelListCommand:
 	case commands.ModelListCommand:
 		modelDialog := dialog.NewModelDialog(a.app)
 		modelDialog := dialog.NewModelDialog(a.app)
 		a.modal = modelDialog
 		a.modal = modelDialog

+ 2 - 1
packages/web/src/components/share/part.module.css

@@ -136,13 +136,14 @@
     flex-grow: 1;
     flex-grow: 1;
     max-width: var(--md-tool-width);
     max-width: var(--md-tool-width);
 
 
-    & > [data-component="assistant-reasoning-markdown"] {
+    [data-component="assistant-reasoning-markdown"] {
       align-self: flex-start;
       align-self: flex-start;
       font-size: 0.875rem;
       font-size: 0.875rem;
       border: 1px solid var(--sl-color-blue-high);
       border: 1px solid var(--sl-color-blue-high);
       padding: 0.5rem calc(0.5rem + 3px);
       padding: 0.5rem calc(0.5rem + 3px);
       border-radius: 0.25rem;
       border-radius: 0.25rem;
       position: relative;
       position: relative;
+      margin-top: 0.5rem;
 
 
       [data-component="copy-button"] {
       [data-component="copy-button"] {
         top: 0.5rem;
         top: 0.5rem;

+ 12 - 9
packages/web/src/components/share/part.tsx

@@ -152,18 +152,23 @@ export function Part(props: PartProps) {
                 )}
                 )}
                 {` | ${props.message.modelID}`}
                 {` | ${props.message.modelID}`}
                 {props.message.mode && (
                 {props.message.mode && (
-                  <span style={{ "font-weight": "bold", color: "var(--sl-color-accent)" }}>
-                    {` | ${props.message.mode}`}
-                  </span>
+                  <span style={{ color: "var(--sl-color-accent)" }}>{` | ${props.message.mode}`}</span>
                 )}
                 )}
               </Footer>
               </Footer>
             )}
             )}
           </div>
           </div>
         )}
         )}
         {props.message.role === "assistant" && props.part.type === "reasoning" && (
         {props.message.role === "assistant" && props.part.type === "reasoning" && (
-          <div data-component="assistant-reasoning">
-            <div data-component="assistant-reasoning-markdown">
-              <ContentMarkdown expand={props.last} text={props.part.text || "Thinking..."} />
+          <div data-component="tool">
+            <div data-component="tool-title">
+              <span data-slot="name">Thinking</span>
+            </div>
+            <div data-component="assistant-reasoning">
+              <ResultsButton showCopy="Show details" hideCopy="Hide details">
+                <div data-component="assistant-reasoning-markdown">
+                  <ContentMarkdown expand text={props.part.text || "Thinking..."} />
+                </div>
+              </ResultsButton>
             </div>
             </div>
           </div>
           </div>
         )}
         )}
@@ -182,9 +187,7 @@ export function Part(props: PartProps) {
               )}
               )}
               {` | ${props.message.modelID}`}
               {` | ${props.message.modelID}`}
               {props.message.mode && (
               {props.message.mode && (
-                <span style={{ "font-weight": "bold", color: "var(--sl-color-accent)" }}>
-                  {` | ${props.message.mode}`}
-                </span>
+                <span style={{ color: "var(--sl-color-accent)" }}>{` | ${props.message.mode}`}</span>
               )}
               )}
             </div>
             </div>
           </div>
           </div>