feat: add chat style

This commit is contained in:
lilong.129
2025-05-17 01:00:40 +08:00
parent 6ceab19fef
commit 8346fb179c
4 changed files with 56 additions and 32 deletions

View File

@@ -1 +1 @@
v5.0.0-beta-2505170008 v5.0.0-beta-2505170100

View File

@@ -311,9 +311,6 @@ func (p *Parser) CallMCPTool(ctx context.Context, serverName,
return nil, fmt.Errorf("mcphost is not initialized") return nil, fmt.Errorf("mcphost is not initialized")
} }
tools := p.MCPHost.GetTools(ctx)
log.Warn().Interface("tools", tools).Msg("tools")
result, err := p.MCPHost.InvokeTool(ctx, serverName, funcName, arguments) result, err := p.MCPHost.InvokeTool(ctx, serverName, funcName, arguments)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "invoke tool %s/%s failed", serverName, funcName) return nil, errors.Wrapf(err, "invoke tool %s/%s failed", serverName, funcName)

View File

@@ -1,7 +1,6 @@
package mcphost package mcphost
import ( import (
"bufio"
"context" "context"
"fmt" "fmt"
"os" "os"
@@ -10,6 +9,7 @@ import (
"github.com/bytedance/sonic" "github.com/bytedance/sonic"
"github.com/charmbracelet/glamour" "github.com/charmbracelet/glamour"
"github.com/charmbracelet/glamour/styles" "github.com/charmbracelet/glamour/styles"
"github.com/charmbracelet/huh"
"github.com/charmbracelet/huh/spinner" "github.com/charmbracelet/huh/spinner"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/list" "github.com/charmbracelet/lipgloss/list"
@@ -24,8 +24,8 @@ import (
"golang.org/x/term" "golang.org/x/term"
) )
// Tokyo Night theme colors
var ( var (
// Tokyo Night theme colors
tokyoPurple = lipgloss.Color("99") // #9d7cd8 tokyoPurple = lipgloss.Color("99") // #9d7cd8
tokyoCyan = lipgloss.Color("73") // #7dcfff tokyoCyan = lipgloss.Color("73") // #7dcfff
tokyoBlue = lipgloss.Color("111") // #7aa2f7 tokyoBlue = lipgloss.Color("111") // #7aa2f7
@@ -36,6 +36,18 @@ var (
tokyoGray = lipgloss.Color("237") // #3b4261 tokyoGray = lipgloss.Color("237") // #3b4261
tokyoBg = lipgloss.Color("234") // #1a1b26 tokyoBg = lipgloss.Color("234") // #1a1b26
promptStyle = lipgloss.NewStyle().
Foreground(tokyoBlue).
PaddingLeft(2)
responseStyle = lipgloss.NewStyle().
Foreground(tokyoFg).
PaddingLeft(2)
errorStyle = lipgloss.NewStyle().
Foreground(tokyoRed).
Bold(true)
toolNameStyle = lipgloss.NewStyle(). toolNameStyle = lipgloss.NewStyle().
Foreground(tokyoCyan). Foreground(tokyoCyan).
Bold(true) Bold(true)
@@ -127,10 +139,25 @@ func (c *Chat) Start() error {
c.showWelcome() c.showWelcome()
for { for {
fmt.Print("\nYou: ") var input string
input, err := readInput() err := huh.NewForm(huh.NewGroup(huh.NewText().
Title("Enter your prompt (Type /help for commands, Ctrl+C to quit)").
Value(&input).
CharLimit(5000)),
).WithWidth(getTerminalWidth()).
WithTheme(huh.ThemeCharm()).
Run()
if err != nil { if err != nil {
return err // Check if it's a user abort (Ctrl+C)
if errors.Is(err, huh.ErrUserAborted) {
fmt.Println("\nGoodbye!")
return nil // Exit cleanly
}
return err // Return other errors normally
}
if input == "" {
continue
} }
// Handle commands // Handle commands
@@ -150,6 +177,8 @@ func (c *Chat) Start() error {
// runPrompt run prompt with MCP tools // runPrompt run prompt with MCP tools
func (c *Chat) runPrompt(prompt string) error { func (c *Chat) runPrompt(prompt string) error {
fmt.Printf("\n%s\n", promptStyle.Render("You: "+prompt))
// Create user message // Create user message
userMsg := &schema.Message{ userMsg := &schema.Message{
Role: schema.User, Role: schema.User,
@@ -158,8 +187,12 @@ func (c *Chat) runPrompt(prompt string) error {
c.history = append(c.history, userMsg) c.history = append(c.history, userMsg)
for { for {
ctx := context.Background() ctx := context.Background()
spinner.New().Type(spinner.Dots).Title("Thinking...").Run() var resp *schema.Message
resp, err := c.model.Generate(ctx, c.history) var err error
action := func() {
resp, err = c.model.Generate(ctx, c.history)
}
_ = spinner.New().Title("Thinking...").Action(action).Run()
if err != nil { if err != nil {
return err return err
} }
@@ -214,10 +247,11 @@ func (c *Chat) runPrompt(prompt string) error {
// Render and display response // Render and display response
if rendered, err := c.renderer.Render(resp.Content); err == nil { if rendered, err := c.renderer.Render(resp.Content); err == nil {
fmt.Printf("\nAssistant: %s\n", rendered) fmt.Printf("\n%s", responseStyle.Render("Assistant: "+rendered))
} else { } else {
fmt.Printf("\nAssistant: %s\n", resp.Content) fmt.Printf("\n%s", errorStyle.Render("Assistant: "+resp.Content))
} }
return nil return nil
} }
} }
@@ -328,7 +362,9 @@ func (c *Chat) showTools() {
} else { } else {
for _, tool := range serverTools.Tools { for _, tool := range serverTools.Tools {
descStyle := lipgloss.NewStyle().Foreground(tokyoFg).Width(contentWidth).Align(lipgloss.Left) descStyle := lipgloss.NewStyle().Foreground(tokyoFg).Width(contentWidth).Align(lipgloss.Left)
toolDesc := list.New().EnumeratorStyle(lipgloss.NewStyle().Foreground(tokyoGreen).MarginRight(1)).Item(descStyle.Render(tool.Description)) toolDesc := list.New().EnumeratorStyle(
lipgloss.NewStyle().Foreground(tokyoGreen).MarginRight(1),
).Item(descStyle.Render(tool.Description))
serverList.Item(toolNameStyle.Render(tool.Name)).Item(toolDesc) serverList.Item(toolNameStyle.Render(tool.Name)).Item(toolDesc)
} }
} }
@@ -354,15 +390,6 @@ func loadSystemPrompt(filePath string) (string, error) {
return string(data), nil return string(data), nil
} }
func readInput() (string, error) {
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')
if err != nil {
return "", err
}
return strings.TrimSpace(input), nil
}
func getTerminalWidth() int { func getTerminalWidth() int {
width, _, err := term.GetSize(int(os.Stdout.Fd())) width, _, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil { if err != nil {

View File

@@ -24,17 +24,17 @@ func TestNewChat(t *testing.T) {
assert.NotNil(t, chat.tools) assert.NotNil(t, chat.tools)
} }
// func TestRunPromptWithNoToolCall(t *testing.T) { func TestRunPromptWithNoToolCall(t *testing.T) {
// host, err := NewMCPHost("./testdata/test.mcp.json") host, err := NewMCPHost("./testdata/test.mcp.json")
// require.NoError(t, err) require.NoError(t, err)
// chat, err := host.NewChat(context.Background(), "") chat, err := host.NewChat(context.Background(), "")
// assert.NoError(t, err) assert.NoError(t, err)
// err = chat.runPrompt("hi") err = chat.runPrompt("hi")
// assert.NoError(t, err) assert.NoError(t, err)
// assert.True(t, len(chat.history) > 1) assert.True(t, len(chat.history) > 1)
// } }
// func TestRunPromptWithToolCall(t *testing.T) { // func TestRunPromptWithToolCall(t *testing.T) {
// host, err := NewMCPHost("./testdata/test.mcp.json") // host, err := NewMCPHost("./testdata/test.mcp.json")