diff --git a/README.md b/README.md index 4f3f3d6..de5f044 100644 --- a/README.md +++ b/README.md @@ -152,12 +152,14 @@ user's request and delegate tasks accordingly. ./bin/sidekick-tui ``` * **Input:** Type your messages at the bottom prompt. +* **Commands:** Type **`/clear`** and press `Enter` to reset the conversation history. * **Markdown:** Agent responses are rendered as formatted Markdown. * **Send:** Press `Enter` to send a message. +* **Cancel:** Press **`Ctrl+D`** while the agent is thinking to cancel the current request. * **Newline:** Press `Ctrl+J` to insert a newline in your message. * **Scrolling:** * Use **`Ctrl+U`** or **`PgUp`** to scroll up. - * Use **`Ctrl+D`** or **`PgDn`** to scroll down. + * Use **`PgDn`** to scroll down. * Mouse wheel is also supported. * **Quit:** Press `Ctrl+C` or `Esc` to exit. diff --git a/agent.go b/agent.go index a918720..55a0fb5 100644 --- a/agent.go +++ b/agent.go @@ -112,6 +112,9 @@ func (s *Sidekick) logIntermediate(msg Message) { if !s.Config.LogIntermediate || s.IntermediateHandler == nil { return } + if msg.Reasoning != "" { + s.IntermediateHandler(fmt.Sprintf("Reasoning: %s", msg.Reasoning)) + } if msg.Content != "" { s.IntermediateHandler(fmt.Sprintf("LLM Output: %s", msg.Content)) } else if len(msg.ToolCalls) > 0 { diff --git a/cmd/sidekick-tui/main.go b/cmd/sidekick-tui/main.go index 460fab8..ab7534a 100644 --- a/cmd/sidekick-tui/main.go +++ b/cmd/sidekick-tui/main.go @@ -426,12 +426,12 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m *model) runAgent() tea.Cmd { - var ctx context.Context - ctx, m.cancel = context.WithCancel(context.Background()) - return func() tea.Msg { - res, err := m.agent.Run(ctx, m.history, m.pool) - return agentResponseMsg{response: res, err: err} - } + var ctx context.Context + ctx, m.cancel = context.WithCancel(context.Background()) + return func() tea.Msg { + res, err := m.agent.Run(ctx, m.history, m.pool) + return agentResponseMsg{response: res, err: err} + } } func (m model) View() string { diff --git a/config.toml b/config.toml index 6ca4279..c87e43b 100644 --- a/config.toml +++ b/config.toml @@ -21,6 +21,16 @@ port = 8080 max_tokens = 4096 timeout_secs = 360 + [models.ollama] + # model_id = "Jackrong/Qwen3.5-2B-Claude-4.6-Opus-Reasoning-Distilled-GGUF:Q4_K_M" + model_id = "LiquidAI/LFM2.5-1.2B-Thinking-GGUF:Q4_K_M" + endpoint = "http://127.0.0.1:8080/v1" + api_key = "" + temperature = 0.6 + max_tokens = 4096 + timeout_secs = 600 + + [mcp_servers] [mcp_servers.context7] transport = "http" @@ -33,7 +43,7 @@ port = 8080 [agents] [agents.coordinator] role = "COORDINATOR" - model_id = "default" + model_id = "ollama" enable_shell_exec = true streaming = false log_intermediate = true @@ -50,7 +60,7 @@ port = 8080 [agents.coder] role = "SPECIALIST" - model_id = "default" + model_id = "ollama" enable_shell_exec = true streaming = false log_intermediate = true @@ -66,7 +76,7 @@ port = 8080 [agents.reviewer] role = "SPECIALIST" - model_id = "fast" + model_id = "ollama" streaming = false log_intermediate = true system_prompt = "You are a Quality Assurance Specialist and Code Reviewer. Your role is to analyze code for potential bugs, security vulnerabilities, and style violations." @@ -81,7 +91,7 @@ port = 8080 [agents.tester] role = "SPECIALIST" - model_id = "fast" + model_id = "ollama" enable_shell_exec = true streaming = false log_intermediate = true diff --git a/llm.go b/llm.go index e860d03..d9c25b0 100644 --- a/llm.go +++ b/llm.go @@ -148,6 +148,7 @@ func (s *standardLLMClient) handleStream(body io.ReadCloser, streamCallback, reasoningCallback func(string)) (Message, error) { defer body.Close() var fullContent strings.Builder + var fullReasoning strings.Builder var finalMsg Message finalMsg.Role = MessageRoleAssistant @@ -178,14 +179,26 @@ func (s *standardLLMClient) handleStream(body io.ReadCloser, streamCallback, var chunk struct { Choices []struct { Delta struct { - Content string `json:"content"` - ToolCalls []deltaToolCall `json:"tool_calls"` + Content string `json:"content"` + ReasoningContent string `json:"reasoning_content"` + Reasoning string `json:"reasoning"` + ToolCalls []deltaToolCall `json:"tool_calls"` } `json:"delta"` } `json:"choices"` } if err := json.Unmarshal([]byte(data), &chunk); err == nil && len(chunk.Choices) > 0 { delta := chunk.Choices[0].Delta - if delta.Content != "" { + + rContent := delta.ReasoningContent + if rContent == "" { + rContent = delta.Reasoning + } + if rContent != "" && reasoningCallback != nil { + fullReasoning.WriteString(rContent) + reasoningCallback(rContent) + } + + if delta.Content != "" && streamCallback != nil { fullContent.WriteString(delta.Content) streamCallback(delta.Content) } @@ -206,6 +219,7 @@ func (s *standardLLMClient) handleStream(body io.ReadCloser, streamCallback, } finalMsg.Content = fullContent.String() + finalMsg.Reasoning = fullReasoning.String() if maxIndex >= 0 { for i := 0; i <= maxIndex; i++ { if tc, ok := toolCallsMap[i]; ok {