diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index a5cd1c6..d055599 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/http" + "regexp" "strings" "time" @@ -127,7 +128,7 @@ func (o *Orchestrator) Send(userMessage string) (string, error) { return "", fmt.Errorf("no response from AI") } - content := chatResp.Choices[0].Message.Content + content := cleanAIResponse(chatResp.Choices[0].Message.Content) o.history = append(o.history, Message{ Role: "assistant", Content: content, @@ -222,6 +223,31 @@ func (o *Orchestrator) ClearHistory() { o.Workflow.Reset() } +func cleanAIResponse(content string) string { + thinkRe := regexp.MustCompile(`(?s)<[Tt]hink[^>]*>.*?`) + content = thinkRe.ReplaceAllString(content, "") + lines := strings.Split(content, "\n") + var clean []string + inBlock := false + for _, line := range lines { + trimmed := strings.TrimSpace(line) + if trimmed == "<<" || trimmed == "<<<" { + inBlock = true + continue + } + if trimmed == ">>" || trimmed == ">>>" { + inBlock = false + continue + } + if inBlock { + continue + } + clean = append(clean, line) + } + result := strings.TrimSpace(strings.Join(clean, "\n")) + return result +} + func getProviderBaseURL(name string) string { switch name { case "minimax": diff --git a/internal/tui/app.go b/internal/tui/app.go index 1cf6252..ee68682 100644 --- a/internal/tui/app.go +++ b/internal/tui/app.go @@ -207,11 +207,11 @@ type keyMap struct { var keys = keyMap{ Tab: key.NewBinding( key.WithKeys("tab"), - key.WithHelp("tab", "next tab"), + key.WithHelp("tab", "indent"), ), Prev: key.NewBinding( key.WithKeys("shift+tab"), - key.WithHelp("shift+tab", "prev tab"), + key.WithHelp("shift+tab", "unindent"), ), Quit: key.NewBinding( key.WithKeys("ctrl+c"), @@ -490,14 +490,6 @@ func (m Model) handleKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { m.tabMenuCursor = int(m.activeTab) m.viewport.SetContent(m.renderContent()) return m, nil - case "tab": - m.activeTab = (m.activeTab + 1) % tabCount - m.resizeViewport() - return m, nil - case "shift+tab": - m.activeTab = (m.activeTab - 1 + tabCount) % tabCount - m.resizeViewport() - return m, nil case "enter": if (m.activeTab == tabChat || m.activeTab == tabWorkflow) && m.chatInput != "" && !m.chatLoading { return m.handleChatSubmit() @@ -597,13 +589,10 @@ func (m Model) handleTerminalKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { } return m, nil case "tab": - m.activeTab = (m.activeTab + 1) % tabCount - m.resizeViewport() - return m, nil - case "shift+tab": - m.activeTab = (m.activeTab - 1 + tabCount) % tabCount - m.resizeViewport() - return m, nil + if m.activeTab == tabChat || m.activeTab == tabWorkflow { + m.chatInput += "\t" + m.viewport.SetContent(m.renderContent()) + } default: if len(msg.String()) == 1 { m.termInput += msg.String() @@ -1685,13 +1674,13 @@ func (m Model) renderFooter() string { case tabDashboard: helpText = "[i] install [u] update [s] scan" case tabChat, tabWorkflow: - helpText = "[ctrl+t] tabs [tab] next [ctrl+c] quit" + helpText = "[ctrl+t] switch tab [ctrl+c] quit" case tabTerminal: helpText = "[enter] run [ctrl+c] kill [clear] clear" case tabAgents: helpText = "[c] crush [l] claude" default: - helpText = "[ctrl+t] tabs [tab] next [ctrl+c] quit" + helpText = "[ctrl+t] switch tab [ctrl+c] quit" } rightR := statusBarStyle.Render(helpText)