mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-14 03:30:26 +00:00
refactor debug messages
This commit is contained in:
+21
-2
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/mark3labs/mcphost/internal/models"
|
||||
"github.com/mark3labs/mcphost/internal/session"
|
||||
"github.com/mark3labs/mcphost/internal/tokens"
|
||||
"github.com/mark3labs/mcphost/internal/tools"
|
||||
"github.com/mark3labs/mcphost/internal/ui"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@@ -386,8 +387,15 @@ func runNormalMode(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// Create the agent using the factory
|
||||
mcpAgent, err := agent.CreateAgent(ctx, &agent.AgentCreationOptions{
|
||||
ModelConfig: modelConfig,
|
||||
// Use a buffered debug logger to capture messages during initialization
|
||||
var bufferedLogger *tools.BufferedDebugLogger
|
||||
var debugLogger tools.DebugLogger
|
||||
if viper.GetBool("debug") {
|
||||
bufferedLogger = tools.NewBufferedDebugLogger(true)
|
||||
debugLogger = bufferedLogger
|
||||
}
|
||||
|
||||
mcpAgent, err := agent.CreateAgent(ctx, &agent.AgentCreationOptions{ModelConfig: modelConfig,
|
||||
MCPConfig: mcpConfig,
|
||||
SystemPrompt: systemPrompt,
|
||||
MaxSteps: viper.GetInt("max-steps"),
|
||||
@@ -395,6 +403,7 @@ func runNormalMode(ctx context.Context) error {
|
||||
ShowSpinner: true,
|
||||
Quiet: quietFlag,
|
||||
SpinnerFunc: spinnerFunc,
|
||||
DebugLogger: debugLogger,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create agent: %v", err)
|
||||
@@ -441,6 +450,16 @@ func runNormalMode(ctx context.Context) error {
|
||||
return fmt.Errorf("failed to setup CLI: %v", err)
|
||||
}
|
||||
|
||||
// Display buffered debug messages if any
|
||||
if bufferedLogger != nil && cli != nil {
|
||||
messages := bufferedLogger.GetMessages()
|
||||
if len(messages) > 0 {
|
||||
// Combine all messages into a single debug output
|
||||
combinedMessage := strings.Join(messages, "\n ")
|
||||
cli.DisplayDebugMessage(combinedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
// Display debug configuration if debug mode is enabled
|
||||
if !quietFlag && cli != nil && viper.GetBool("debug") {
|
||||
debugConfig := map[string]any{
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/mark3labs/mcphost/internal/config"
|
||||
"github.com/mark3labs/mcphost/internal/hooks"
|
||||
"github.com/mark3labs/mcphost/internal/models"
|
||||
"github.com/mark3labs/mcphost/internal/tools"
|
||||
"github.com/mark3labs/mcphost/internal/ui"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@@ -596,6 +597,12 @@ func runScriptMode(ctx context.Context, mcpConfig *config.Config, prompt string,
|
||||
}
|
||||
|
||||
// Create the agent using the factory (scripts don't need spinners)
|
||||
// Use a simple debug logger for scripts
|
||||
var debugLogger tools.DebugLogger
|
||||
if finalDebug {
|
||||
debugLogger = tools.NewSimpleDebugLogger(true)
|
||||
}
|
||||
|
||||
mcpAgent, err := agent.CreateAgent(ctx, &agent.AgentCreationOptions{
|
||||
ModelConfig: modelConfig,
|
||||
MCPConfig: mcpConfig,
|
||||
@@ -605,6 +612,7 @@ func runScriptMode(ctx context.Context, mcpConfig *config.Config, prompt string,
|
||||
ShowSpinner: false, // Scripts don't need spinners
|
||||
Quiet: quietFlag,
|
||||
SpinnerFunc: nil, // No spinner function needed
|
||||
DebugLogger: debugLogger,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create agent: %v", err)
|
||||
|
||||
@@ -23,6 +23,7 @@ type AgentConfig struct {
|
||||
SystemPrompt string
|
||||
MaxSteps int
|
||||
StreamingEnabled bool
|
||||
DebugLogger tools.DebugLogger // Optional debug logger
|
||||
}
|
||||
|
||||
// ToolCallHandler is a function type for handling tool calls as they happen
|
||||
@@ -68,6 +69,11 @@ func NewAgent(ctx context.Context, config *AgentConfig) (*Agent, error) {
|
||||
// Set the model for sampling support
|
||||
toolManager.SetModel(providerResult.Model)
|
||||
|
||||
// Set the debug logger if provided
|
||||
if config.DebugLogger != nil {
|
||||
toolManager.SetDebugLogger(config.DebugLogger)
|
||||
}
|
||||
|
||||
if err := toolManager.LoadTools(ctx, config.MCPConfig); err != nil {
|
||||
return nil, fmt.Errorf("failed to load MCP tools: %v", err)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/mark3labs/mcphost/internal/config"
|
||||
"github.com/mark3labs/mcphost/internal/models"
|
||||
"github.com/mark3labs/mcphost/internal/tools"
|
||||
)
|
||||
|
||||
// SpinnerFunc is a function type for showing spinners during agent creation
|
||||
@@ -19,9 +20,10 @@ type AgentCreationOptions struct {
|
||||
SystemPrompt string
|
||||
MaxSteps int
|
||||
StreamingEnabled bool
|
||||
ShowSpinner bool // For Ollama models
|
||||
Quiet bool // Skip spinner if quiet
|
||||
SpinnerFunc SpinnerFunc // Function to show spinner (provided by caller)
|
||||
ShowSpinner bool // For Ollama models
|
||||
Quiet bool // Skip spinner if quiet
|
||||
SpinnerFunc SpinnerFunc // Function to show spinner (provided by caller)
|
||||
DebugLogger tools.DebugLogger // Optional debug logger
|
||||
}
|
||||
|
||||
// CreateAgent creates an agent with optional spinner for Ollama models
|
||||
@@ -32,6 +34,7 @@ func CreateAgent(ctx context.Context, opts *AgentCreationOptions) (*Agent, error
|
||||
SystemPrompt: opts.SystemPrompt,
|
||||
MaxSteps: opts.MaxSteps,
|
||||
StreamingEnabled: opts.StreamingEnabled,
|
||||
DebugLogger: opts.DebugLogger,
|
||||
}
|
||||
|
||||
var agent *Agent
|
||||
|
||||
+1502
-1502
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// BufferedDebugLogger stores debug messages until they can be displayed
|
||||
type BufferedDebugLogger struct {
|
||||
enabled bool
|
||||
messages []string
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// NewBufferedDebugLogger creates a new buffered debug logger
|
||||
func NewBufferedDebugLogger(enabled bool) *BufferedDebugLogger {
|
||||
return &BufferedDebugLogger{
|
||||
enabled: enabled,
|
||||
messages: make([]string, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// LogDebug stores a debug message
|
||||
func (l *BufferedDebugLogger) LogDebug(message string) {
|
||||
if !l.enabled {
|
||||
return
|
||||
}
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
l.messages = append(l.messages, message)
|
||||
}
|
||||
|
||||
// IsDebugEnabled returns whether debug logging is enabled
|
||||
func (l *BufferedDebugLogger) IsDebugEnabled() bool {
|
||||
return l.enabled
|
||||
}
|
||||
|
||||
// GetMessages returns all buffered messages and clears the buffer
|
||||
func (l *BufferedDebugLogger) GetMessages() []string {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
messages := make([]string, len(l.messages))
|
||||
copy(messages, l.messages)
|
||||
l.messages = l.messages[:0] // Clear the buffer
|
||||
return messages
|
||||
}
|
||||
@@ -55,10 +55,12 @@ type MCPConnectionPool struct {
|
||||
model model.ToolCallingChatModel
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
debug bool
|
||||
debugLogger DebugLogger
|
||||
}
|
||||
|
||||
// NewMCPConnectionPool creates a new connection pool
|
||||
func NewMCPConnectionPool(config *ConnectionPoolConfig, model model.ToolCallingChatModel) *MCPConnectionPool {
|
||||
func NewMCPConnectionPool(config *ConnectionPoolConfig, model model.ToolCallingChatModel, debug bool) *MCPConnectionPool {
|
||||
if config == nil {
|
||||
config = DefaultConnectionPoolConfig()
|
||||
}
|
||||
@@ -70,12 +72,20 @@ func NewMCPConnectionPool(config *ConnectionPoolConfig, model model.ToolCallingC
|
||||
model: model,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
debug: debug,
|
||||
}
|
||||
|
||||
go pool.startHealthCheck()
|
||||
return pool
|
||||
}
|
||||
|
||||
// SetDebugLogger sets the debug logger for the connection pool
|
||||
func (p *MCPConnectionPool) SetDebugLogger(logger DebugLogger) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
p.debugLogger = logger
|
||||
}
|
||||
|
||||
// GetConnection gets a connection from the pool
|
||||
func (p *MCPConnectionPool) GetConnection(ctx context.Context, serverName string, serverConfig config.MCPServerConfig) (*MCPConnection, error) {
|
||||
p.mu.Lock()
|
||||
@@ -90,16 +100,24 @@ func (p *MCPConnectionPool) GetConnection(ctx context.Context, serverName string
|
||||
conn.mu.Lock()
|
||||
conn.lastUsed = time.Now()
|
||||
conn.mu.Unlock()
|
||||
fmt.Printf("🔄 [POOL] Reusing connection for %s\n", serverName)
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug(fmt.Sprintf("[POOL] Reusing connection for %s", serverName))
|
||||
}
|
||||
return conn, nil
|
||||
} else {
|
||||
fmt.Printf("🔍 [POOL] Connection %s unhealthy, removing\n", serverName)
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug(fmt.Sprintf("[POOL] Connection %s unhealthy, removing", serverName))
|
||||
}
|
||||
}
|
||||
conn.client.Close()
|
||||
delete(p.connections, serverName)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("🆕 [POOL] Creating new connection for %s\n", serverName)
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug(fmt.Sprintf("[POOL] Creating new connection for %s", serverName))
|
||||
}
|
||||
conn, err := p.createConnection(ctx, serverName, serverConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create connection for %s: %w", serverName, err)
|
||||
@@ -125,10 +143,14 @@ func (p *MCPConnectionPool) GetConnectionWithHealthCheck(ctx context.Context, se
|
||||
conn.mu.Lock()
|
||||
conn.lastUsed = time.Now()
|
||||
conn.mu.Unlock()
|
||||
fmt.Printf("✅ [POOL] Reusing healthy connection for %s\n", serverName)
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug(fmt.Sprintf("[POOL] Reusing healthy connection for %s", serverName))
|
||||
}
|
||||
return conn, nil
|
||||
} else {
|
||||
fmt.Printf("🔍 [POOL] Connection %s failed health check, removing\n", serverName)
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug(fmt.Sprintf("[POOL] Connection %s failed health check, removing", serverName))
|
||||
}
|
||||
conn.client.Close()
|
||||
delete(p.connections, serverName)
|
||||
}
|
||||
@@ -139,7 +161,9 @@ func (p *MCPConnectionPool) GetConnectionWithHealthCheck(ctx context.Context, se
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("🆕 [POOL] Creating new connection for %s\n", serverName)
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug(fmt.Sprintf("[POOL] Creating new connection for %s", serverName))
|
||||
}
|
||||
conn, err := p.createConnection(ctx, serverName, serverConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create connection for %s: %w", serverName, err)
|
||||
@@ -198,7 +222,9 @@ func (p *MCPConnectionPool) createConnection(ctx context.Context, serverName str
|
||||
lastError: nil,
|
||||
}
|
||||
|
||||
fmt.Printf("✅ [POOL] Created connection for %s\n", serverName)
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug(fmt.Sprintf("[POOL] Created connection for %s", serverName))
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
@@ -349,7 +375,9 @@ func (p *MCPConnectionPool) initializeClient(ctx context.Context, client client.
|
||||
return fmt.Errorf("initialization timeout or failed: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("✅ [POOL] Initialized MCP client\n")
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug(fmt.Sprintf("[POOL] Initialized MCP client"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -412,10 +440,14 @@ func (p *MCPConnectionPool) HandleConnectionError(serverName string, err error)
|
||||
|
||||
if isConnectionError(err) {
|
||||
conn.isHealthy = false
|
||||
fmt.Printf("❌ [POOL] Connection %s marked as unhealthy: %v\n", serverName, err)
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug(fmt.Sprintf("[POOL] Connection %s unhealthy, removing", serverName))
|
||||
}
|
||||
|
||||
if strings.Contains(err.Error(), "404") {
|
||||
fmt.Printf("🔄 [POOL] 404 error for %s, will recreate on next request\n", serverName)
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug(fmt.Sprintf("[POOL] 404 error for %s, will recreate on next request", serverName))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -466,11 +498,15 @@ func (p *MCPConnectionPool) Close() error {
|
||||
|
||||
for name, conn := range p.connections {
|
||||
if err := conn.client.Close(); err != nil {
|
||||
fmt.Printf("⚠️ [POOL] Failed to close connection %s: %v\n", name, err)
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug(fmt.Sprintf("[POOL] Failed to close connection %s: %v", name, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("🛑 [POOL] Connection pool closed\n")
|
||||
if p.debugLogger != nil && p.debugLogger.IsDebugEnabled() {
|
||||
p.debugLogger.LogDebug("[POOL] Connection pool closed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package tools
|
||||
|
||||
// DebugLogger interface for debug logging
|
||||
type DebugLogger interface {
|
||||
LogDebug(message string)
|
||||
IsDebugEnabled() bool
|
||||
}
|
||||
|
||||
// SimpleDebugLogger is a simple implementation that prints to stdout
|
||||
type SimpleDebugLogger struct {
|
||||
enabled bool
|
||||
}
|
||||
|
||||
// NewSimpleDebugLogger creates a new simple debug logger
|
||||
func NewSimpleDebugLogger(enabled bool) *SimpleDebugLogger {
|
||||
return &SimpleDebugLogger{enabled: enabled}
|
||||
}
|
||||
|
||||
// LogDebug logs a debug message
|
||||
func (l *SimpleDebugLogger) LogDebug(message string) {
|
||||
// Silent by default - messages will only appear when using CLI debug logger
|
||||
// This prevents duplicate or unstyled debug output during initialization
|
||||
}
|
||||
|
||||
// IsDebugEnabled returns whether debug logging is enabled
|
||||
func (l *SimpleDebugLogger) IsDebugEnabled() bool {
|
||||
return l.enabled
|
||||
}
|
||||
+28
-9
@@ -26,6 +26,8 @@ type MCPToolManager struct {
|
||||
toolMap map[string]*toolMapping // maps prefixed tool names to their server and original name
|
||||
model model.ToolCallingChatModel // LLM model for sampling
|
||||
config *config.Config
|
||||
debug bool
|
||||
debugLogger DebugLogger
|
||||
}
|
||||
|
||||
// toolMapping stores the mapping between prefixed tool names and their original details
|
||||
@@ -55,6 +57,14 @@ func (m *MCPToolManager) SetModel(model model.ToolCallingChatModel) {
|
||||
m.model = model
|
||||
}
|
||||
|
||||
// SetDebugLogger sets the debug logger
|
||||
func (m *MCPToolManager) SetDebugLogger(logger DebugLogger) {
|
||||
m.debugLogger = logger
|
||||
if m.connectionPool != nil {
|
||||
m.connectionPool.SetDebugLogger(logger)
|
||||
}
|
||||
}
|
||||
|
||||
// samplingHandler implements the MCP sampling handler interface
|
||||
type samplingHandler struct {
|
||||
model model.ToolCallingChatModel
|
||||
@@ -120,7 +130,12 @@ func (h *samplingHandler) CreateMessage(ctx context.Context, request mcp.CreateM
|
||||
func (m *MCPToolManager) LoadTools(ctx context.Context, config *config.Config) error {
|
||||
// Initialize connection pool
|
||||
m.config = config
|
||||
m.connectionPool = NewMCPConnectionPool(DefaultConnectionPoolConfig(), m.model)
|
||||
m.debug = config.Debug
|
||||
if m.debugLogger == nil {
|
||||
m.debugLogger = NewSimpleDebugLogger(config.Debug)
|
||||
}
|
||||
m.connectionPool = NewMCPConnectionPool(DefaultConnectionPoolConfig(), m.model, config.Debug)
|
||||
m.connectionPool.SetDebugLogger(m.debugLogger)
|
||||
|
||||
var loadErrors []string
|
||||
|
||||
@@ -143,7 +158,7 @@ func (m *MCPToolManager) LoadTools(ctx context.Context, config *config.Config) e
|
||||
// loadServerTools loads tools from a single MCP server
|
||||
func (m *MCPToolManager) loadServerTools(ctx context.Context, serverName string, serverConfig config.MCPServerConfig) error {
|
||||
// Add debug logging
|
||||
debugLogConnectionInfo(serverName, serverConfig)
|
||||
m.debugLogConnectionInfo(serverName, serverConfig)
|
||||
|
||||
// Get connection from pool
|
||||
conn, err := m.connectionPool.GetConnection(ctx, serverName, serverConfig)
|
||||
@@ -485,22 +500,26 @@ func (m *MCPToolManager) createBuiltinClient(ctx context.Context, serverName str
|
||||
}
|
||||
|
||||
// debugLogConnectionInfo logs detailed connection information for debugging
|
||||
func debugLogConnectionInfo(serverName string, serverConfig config.MCPServerConfig) {
|
||||
fmt.Printf("🔍 [DEBUG] Connecting to MCP server: %s\n", serverName)
|
||||
fmt.Printf("🔍 [DEBUG] Transport type: %s\n", serverConfig.GetTransportType())
|
||||
func (m *MCPToolManager) debugLogConnectionInfo(serverName string, serverConfig config.MCPServerConfig) {
|
||||
if m.debugLogger == nil || !m.debugLogger.IsDebugEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
m.debugLogger.LogDebug(fmt.Sprintf("[DEBUG] Connecting to MCP server: %s", serverName))
|
||||
m.debugLogger.LogDebug(fmt.Sprintf("[DEBUG] Transport type: %s", serverConfig.GetTransportType()))
|
||||
|
||||
switch serverConfig.GetTransportType() {
|
||||
case "stdio":
|
||||
if len(serverConfig.Command) > 0 {
|
||||
fmt.Printf("🔍 [DEBUG] Command: %s %v\n", serverConfig.Command[0], serverConfig.Command[1:])
|
||||
m.debugLogger.LogDebug(fmt.Sprintf("[DEBUG] Command: %s %v", serverConfig.Command[0], serverConfig.Command[1:]))
|
||||
}
|
||||
if len(serverConfig.Environment) > 0 {
|
||||
fmt.Printf("🔍 [DEBUG] Environment variables: %d\n", len(serverConfig.Environment))
|
||||
m.debugLogger.LogDebug(fmt.Sprintf("[DEBUG] Environment variables: %d", len(serverConfig.Environment)))
|
||||
}
|
||||
case "sse", "streamable":
|
||||
fmt.Printf("🔍 [DEBUG] URL: %s\n", serverConfig.URL)
|
||||
m.debugLogger.LogDebug(fmt.Sprintf("[DEBUG] URL: %s", serverConfig.URL))
|
||||
if len(serverConfig.Headers) > 0 {
|
||||
fmt.Printf("🔍 [DEBUG] Headers: %v\n", serverConfig.Headers)
|
||||
m.debugLogger.LogDebug(fmt.Sprintf("[DEBUG] Headers: %v", serverConfig.Headers))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ type CLI struct {
|
||||
width int
|
||||
height int
|
||||
compactMode bool // Add compact mode flag
|
||||
debug bool // Add debug mode flag
|
||||
modelName string // Store current model name
|
||||
lastStreamHeight int // track how far back we need to move the cursor to overwrite streaming messages
|
||||
usageDisplayed bool // track if usage info was displayed after last assistant message
|
||||
@@ -35,6 +36,7 @@ type CLI struct {
|
||||
func NewCLI(debug bool, compact bool) (*CLI, error) {
|
||||
cli := &CLI{
|
||||
compactMode: compact,
|
||||
debug: debug,
|
||||
}
|
||||
cli.updateSize()
|
||||
cli.messageRenderer = NewMessageRenderer(cli.width, debug)
|
||||
@@ -52,6 +54,11 @@ func (c *CLI) SetUsageTracker(tracker *UsageTracker) {
|
||||
}
|
||||
}
|
||||
|
||||
// GetDebugLogger returns a debug logger that uses the CLI for rendering
|
||||
func (c *CLI) GetDebugLogger() *CLIDebugLogger {
|
||||
return NewCLIDebugLogger(c)
|
||||
}
|
||||
|
||||
// SetModelName sets the current model name for the CLI
|
||||
func (c *CLI) SetModelName(modelName string) {
|
||||
c.modelName = modelName
|
||||
@@ -232,6 +239,21 @@ func (c *CLI) DisplayCancellation() {
|
||||
c.displayContainer()
|
||||
}
|
||||
|
||||
// DisplayDebugMessage displays debug messages using the appropriate renderer
|
||||
func (c *CLI) DisplayDebugMessage(message string) {
|
||||
if !c.debug {
|
||||
return
|
||||
}
|
||||
var msg UIMessage
|
||||
if c.compactMode {
|
||||
msg = c.compactRenderer.RenderDebugMessage(message, time.Now())
|
||||
} else {
|
||||
msg = c.messageRenderer.RenderDebugMessage(message, time.Now())
|
||||
}
|
||||
c.messageContainer.AddMessage(msg)
|
||||
c.displayContainer()
|
||||
}
|
||||
|
||||
// DisplayDebugConfig displays configuration settings using the appropriate renderer
|
||||
func (c *CLI) DisplayDebugConfig(config map[string]any) {
|
||||
var msg UIMessage
|
||||
|
||||
@@ -201,6 +201,28 @@ func (r *CompactRenderer) RenderErrorMessage(errorMsg string, timestamp time.Tim
|
||||
}
|
||||
}
|
||||
|
||||
// RenderDebugMessage renders debug messages in compact format
|
||||
func (r *CompactRenderer) RenderDebugMessage(message string, timestamp time.Time) UIMessage {
|
||||
theme := getTheme()
|
||||
symbol := lipgloss.NewStyle().Foreground(theme.Tool).Render("*")
|
||||
label := lipgloss.NewStyle().Foreground(theme.Tool).Bold(true).Render("Debug")
|
||||
|
||||
// Truncate message if too long
|
||||
content := message
|
||||
if len(content) > r.width-20 {
|
||||
content = content[:r.width-23] + "..."
|
||||
}
|
||||
|
||||
line := fmt.Sprintf("%s %-8s %s", symbol, label, content)
|
||||
|
||||
return UIMessage{
|
||||
Type: SystemMessage,
|
||||
Content: line,
|
||||
Height: 1,
|
||||
Timestamp: timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
// RenderDebugConfigMessage renders debug config in compact format
|
||||
func (r *CompactRenderer) RenderDebugConfigMessage(config map[string]any, timestamp time.Time) UIMessage {
|
||||
theme := getTheme()
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CLIDebugLogger implements the tools.DebugLogger interface using CLI rendering
|
||||
type CLIDebugLogger struct {
|
||||
cli *CLI
|
||||
}
|
||||
|
||||
// NewCLIDebugLogger creates a new CLI debug logger
|
||||
func NewCLIDebugLogger(cli *CLI) *CLIDebugLogger {
|
||||
return &CLIDebugLogger{cli: cli}
|
||||
}
|
||||
|
||||
// LogDebug logs a debug message using the CLI's debug message renderer
|
||||
func (l *CLIDebugLogger) LogDebug(message string) {
|
||||
if l.cli == nil || !l.cli.debug {
|
||||
return
|
||||
}
|
||||
|
||||
// Format the message to include all the debug info in a structured way
|
||||
var formattedMessage string
|
||||
|
||||
// Check if this is a multi-line debug output (like connection info)
|
||||
if strings.Contains(message, "[DEBUG]") || strings.Contains(message, "[POOL]") {
|
||||
// Extract the tag and content
|
||||
if strings.HasPrefix(message, "[DEBUG]") {
|
||||
content := strings.TrimPrefix(message, "[DEBUG]")
|
||||
content = strings.TrimSpace(content)
|
||||
formattedMessage = fmt.Sprintf("🔍 DEBUG: %s", content)
|
||||
} else if strings.HasPrefix(message, "[POOL]") {
|
||||
content := strings.TrimPrefix(message, "[POOL]")
|
||||
content = strings.TrimSpace(content)
|
||||
|
||||
// Add appropriate emoji based on the message content
|
||||
if strings.Contains(content, "Creating new connection") {
|
||||
formattedMessage = fmt.Sprintf("🆕 POOL: %s", content)
|
||||
} else if strings.Contains(content, "Created connection") || strings.Contains(content, "Initialized") {
|
||||
formattedMessage = fmt.Sprintf("✅ POOL: %s", content)
|
||||
} else if strings.Contains(content, "Reusing") {
|
||||
formattedMessage = fmt.Sprintf("🔄 POOL: %s", content)
|
||||
} else if strings.Contains(content, "unhealthy") || strings.Contains(content, "failed") {
|
||||
formattedMessage = fmt.Sprintf("❌ POOL: %s", content)
|
||||
} else if strings.Contains(content, "closed") {
|
||||
formattedMessage = fmt.Sprintf("🛑 POOL: %s", content)
|
||||
} else if strings.Contains(content, "Failed to close") {
|
||||
formattedMessage = fmt.Sprintf("⚠️ POOL: %s", content)
|
||||
} else {
|
||||
formattedMessage = fmt.Sprintf("🔍 POOL: %s", content)
|
||||
}
|
||||
} else {
|
||||
formattedMessage = message
|
||||
}
|
||||
} else {
|
||||
formattedMessage = message
|
||||
}
|
||||
|
||||
// Use the CLI's debug message rendering
|
||||
var msg UIMessage
|
||||
if l.cli.compactMode {
|
||||
msg = l.cli.compactRenderer.RenderDebugMessage(formattedMessage, time.Now())
|
||||
} else {
|
||||
msg = l.cli.messageRenderer.RenderDebugMessage(formattedMessage, time.Now())
|
||||
}
|
||||
l.cli.messageContainer.AddMessage(msg)
|
||||
l.cli.displayContainer()
|
||||
}
|
||||
|
||||
// IsDebugEnabled returns whether debug logging is enabled
|
||||
func (l *CLIDebugLogger) IsDebugEnabled() bool {
|
||||
return l.cli != nil && l.cli.debug
|
||||
}
|
||||
@@ -193,6 +193,64 @@ func (r *MessageRenderer) RenderSystemMessage(content string, timestamp time.Tim
|
||||
}
|
||||
}
|
||||
|
||||
// RenderDebugMessage renders debug messages with tool response block styling
|
||||
func (r *MessageRenderer) RenderDebugMessage(message string, timestamp time.Time) UIMessage {
|
||||
baseStyle := lipgloss.NewStyle()
|
||||
|
||||
// Create the main message style with border using tool color
|
||||
theme := getTheme()
|
||||
style := baseStyle.
|
||||
Width(r.width - 3). // Account for left margin
|
||||
BorderLeft(true).
|
||||
Foreground(theme.Muted).
|
||||
BorderForeground(theme.Tool).
|
||||
BorderStyle(lipgloss.ThickBorder()).
|
||||
PaddingLeft(1).
|
||||
MarginLeft(2). // Add left margin like other messages
|
||||
MarginBottom(1) // Add bottom margin
|
||||
|
||||
// Format timestamp
|
||||
timeStr := timestamp.Local().Format("02 Jan 2006 03:04 PM")
|
||||
|
||||
// Create header with debug icon
|
||||
header := baseStyle.
|
||||
Foreground(theme.Tool).
|
||||
Bold(true).
|
||||
Render("🔍 Debug Output")
|
||||
|
||||
// Process and format the message content
|
||||
// Split into lines and format each one
|
||||
lines := strings.Split(message, "\n")
|
||||
var formattedLines []string
|
||||
for _, line := range lines {
|
||||
if strings.TrimSpace(line) != "" {
|
||||
formattedLines = append(formattedLines, " "+line)
|
||||
}
|
||||
}
|
||||
|
||||
content := baseStyle.
|
||||
Foreground(theme.Muted).
|
||||
Render(strings.Join(formattedLines, "\n"))
|
||||
|
||||
// Create info line
|
||||
info := baseStyle.
|
||||
Width(r.width - 5). // Account for margins and padding
|
||||
Foreground(theme.Muted).
|
||||
Render(fmt.Sprintf(" MCPHost (%s)", timeStr))
|
||||
|
||||
// Combine all parts
|
||||
fullContent := lipgloss.JoinVertical(lipgloss.Left,
|
||||
header,
|
||||
content,
|
||||
info,
|
||||
)
|
||||
|
||||
return UIMessage{
|
||||
Content: style.Render(fullContent),
|
||||
Height: lipgloss.Height(style.Render(fullContent)),
|
||||
}
|
||||
}
|
||||
|
||||
// RenderDebugConfigMessage renders debug configuration settings with tool response block styling
|
||||
func (r *MessageRenderer) RenderDebugConfigMessage(config map[string]any, timestamp time.Time) UIMessage {
|
||||
baseStyle := lipgloss.NewStyle()
|
||||
|
||||
Reference in New Issue
Block a user