summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authoradamdotdevin <[email protected]>2025-08-11 11:58:40 -0500
committeradamdotdevin <[email protected]>2025-08-11 11:58:46 -0500
commit5e777fd2a2d821003bfc7aa39bf5c5cd158b6c5b (patch)
tree0e68ca9beaba0715219e1e1c1d20479b5d708d9a /packages
parent3c71fda6481bcadcf62278478f0678002ff9029a (diff)
downloadopencode-5e777fd2a2d821003bfc7aa39bf5c5cd158b6c5b.tar.gz
opencode-5e777fd2a2d821003bfc7aa39bf5c5cd158b6c5b.zip
feat: toggle tool details visible
Diffstat (limited to 'packages')
-rw-r--r--packages/opencode/src/config/config.ts1
-rw-r--r--packages/opencode/src/session/index.ts4
-rw-r--r--packages/tui/internal/app/state.go2
-rw-r--r--packages/tui/internal/commands/command.go7
-rw-r--r--packages/tui/internal/components/chat/messages.go114
-rw-r--r--packages/tui/internal/tui/tui.go7
-rw-r--r--packages/web/src/components/share/part.module.css3
-rw-r--r--packages/web/src/components/share/part.tsx21
8 files changed, 102 insertions, 57 deletions
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index 0eaae2b79..40ec22b57 100644
--- a/packages/opencode/src/config/config.ts
+++ b/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_compact: z.string().optional().default("<leader>c").describe("Compact the session"),
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"),
theme_list: z.string().optional().default("<leader>t").describe("List available themes"),
file_list: z.string().optional().default("<leader>f").describe("List files"),
diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts
index 5565f3e0a..5f7bf000d 100644
--- a/packages/opencode/src/session/index.ts
+++ b/packages/opencode/src/session/index.ts
@@ -1007,7 +1007,7 @@ export namespace Session {
async process(stream: StreamTextResult<Record<string, AITool>, never>) {
try {
let currentText: MessageV2.TextPart | undefined
- // let reasoningMap: Record<string, MessageV2.ReasoningPart> = {}
+ let reasoningMap: Record<string, MessageV2.ReasoningPart> = {}
for await (const value of stream.fullStream) {
log.info("part", {
@@ -1017,7 +1017,6 @@ export namespace Session {
case "start":
break
- /*
case "reasoning-start":
if (value.id in reasoningMap) {
continue
@@ -1055,7 +1054,6 @@ export namespace Session {
delete reasoningMap[value.id]
}
break
- */
case "tool-input-start":
const part = await updatePart({
diff --git a/packages/tui/internal/app/state.go b/packages/tui/internal/app/state.go
index 478022351..283cbd15e 100644
--- a/packages/tui/internal/app/state.go
+++ b/packages/tui/internal/app/state.go
@@ -32,6 +32,8 @@ type State struct {
MessagesRight bool `toml:"messages_right"`
SplitDiff bool `toml:"split_diff"`
MessageHistory []Prompt `toml:"message_history"`
+ ShowToolDetails *bool `toml:"show_tool_details"`
+ ShowThinkingBlocks *bool `toml:"show_thinking_blocks"`
}
func NewState() *State {
diff --git a/packages/tui/internal/commands/command.go b/packages/tui/internal/commands/command.go
index 516caab79..fff547543 100644
--- a/packages/tui/internal/commands/command.go
+++ b/packages/tui/internal/commands/command.go
@@ -119,6 +119,7 @@ const (
SessionCompactCommand CommandName = "session_compact"
SessionExportCommand CommandName = "session_export"
ToolDetailsCommand CommandName = "tool_details"
+ ThinkingBlocksCommand CommandName = "thinking_blocks"
ModelListCommand CommandName = "model_list"
AgentListCommand CommandName = "agent_list"
ModelCycleRecentCommand CommandName = "model_cycle_recent"
@@ -246,6 +247,12 @@ func LoadFromConfig(config *opencode.Config) CommandRegistry {
Trigger: []string{"details"},
},
{
+ Name: ThinkingBlocksCommand,
+ Description: "toggle thinking blocks",
+ Keybindings: parseBindings("<leader>b"),
+ Trigger: []string{"thinking"},
+ },
+ {
Name: ModelListCommand,
Description: "list models",
Keybindings: parseBindings("<leader>m"),
diff --git a/packages/tui/internal/components/chat/messages.go b/packages/tui/internal/components/chat/messages.go
index 84c3b9830..bbfd557a6 100644
--- a/packages/tui/internal/components/chat/messages.go
+++ b/packages/tui/internal/components/chat/messages.go
@@ -33,6 +33,7 @@ type MessagesComponent interface {
HalfPageUp() (tea.Model, tea.Cmd)
HalfPageDown() (tea.Model, tea.Cmd)
ToolDetailsVisible() bool
+ ThinkingBlocksVisible() bool
GotoTop() (tea.Model, tea.Cmd)
GotoBottom() (tea.Model, tea.Cmd)
CopyLastMessage() (tea.Model, tea.Cmd)
@@ -41,20 +42,21 @@ type MessagesComponent interface {
}
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 {
@@ -94,6 +96,7 @@ func (s selection) coords(offset int) *selection {
}
type ToggleToolDetailsMsg struct{}
+type ToggleThinkingBlocksMsg struct{}
func (m *messagesComponent) Init() tea.Cmd {
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()
case ToggleToolDetailsMsg:
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:
m.cache.Clear()
m.tail = true
@@ -561,32 +569,34 @@ func (m *messagesComponent) renderView() tea.Cmd {
if reverted {
continue
}
- text := "..."
+ if !m.showThinkingBlocks {
+ continue
+ }
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
}
+func (m *messagesComponent) ThinkingBlocksVisible() bool {
+ return m.showThinkingBlocks
+}
+
func (m *messagesComponent) GotoTop() (tea.Model, tea.Cmd) {
m.viewport.GotoTop()
return m, nil
@@ -1202,11 +1216,23 @@ func NewMessagesComponent(app *app.App) MessagesComponent {
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{
- app: app,
- viewport: vp,
- showToolDetails: true,
- cache: NewPartCache(),
- tail: true,
+ app: app,
+ viewport: vp,
+ showToolDetails: showToolDetails,
+ showThinkingBlocks: showThinkingBlocks,
+ cache: NewPartCache(),
+ tail: true,
}
}
diff --git a/packages/tui/internal/tui/tui.go b/packages/tui/internal/tui/tui.go
index 499d67c65..1899df351 100644
--- a/packages/tui/internal/tui/tui.go
+++ b/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, 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:
modelDialog := dialog.NewModelDialog(a.app)
a.modal = modelDialog
diff --git a/packages/web/src/components/share/part.module.css b/packages/web/src/components/share/part.module.css
index 3dd321425..15a43da36 100644
--- a/packages/web/src/components/share/part.module.css
+++ b/packages/web/src/components/share/part.module.css
@@ -136,13 +136,14 @@
flex-grow: 1;
max-width: var(--md-tool-width);
- & > [data-component="assistant-reasoning-markdown"] {
+ [data-component="assistant-reasoning-markdown"] {
align-self: flex-start;
font-size: 0.875rem;
border: 1px solid var(--sl-color-blue-high);
padding: 0.5rem calc(0.5rem + 3px);
border-radius: 0.25rem;
position: relative;
+ margin-top: 0.5rem;
[data-component="copy-button"] {
top: 0.5rem;
diff --git a/packages/web/src/components/share/part.tsx b/packages/web/src/components/share/part.tsx
index 5cfd3a045..597b67d67 100644
--- a/packages/web/src/components/share/part.tsx
+++ b/packages/web/src/components/share/part.tsx
@@ -152,18 +152,23 @@ export function Part(props: PartProps) {
)}
{` | ${props.message.modelID}`}
{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>
)}
</div>
)}
{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>
)}
@@ -182,9 +187,7 @@ export function Part(props: PartProps) {
)}
{` | ${props.message.modelID}`}
{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>