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,7 +1,6 @@
package mcphost
import (
"bufio"
"context"
"fmt"
"os"
@@ -10,6 +9,7 @@ import (
"github.com/bytedance/sonic"
"github.com/charmbracelet/glamour"
"github.com/charmbracelet/glamour/styles"
"github.com/charmbracelet/huh"
"github.com/charmbracelet/huh/spinner"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/list"
@@ -24,8 +24,8 @@ import (
"golang.org/x/term"
)
// Tokyo Night theme colors
var (
// Tokyo Night theme colors
tokyoPurple = lipgloss.Color("99") // #9d7cd8
tokyoCyan = lipgloss.Color("73") // #7dcfff
tokyoBlue = lipgloss.Color("111") // #7aa2f7
@@ -36,6 +36,18 @@ var (
tokyoGray = lipgloss.Color("237") // #3b4261
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().
Foreground(tokyoCyan).
Bold(true)
@@ -127,10 +139,25 @@ func (c *Chat) Start() error {
c.showWelcome()
for {
fmt.Print("\nYou: ")
input, err := readInput()
var input string
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 {
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
@@ -150,6 +177,8 @@ func (c *Chat) Start() error {
// runPrompt run prompt with MCP tools
func (c *Chat) runPrompt(prompt string) error {
fmt.Printf("\n%s\n", promptStyle.Render("You: "+prompt))
// Create user message
userMsg := &schema.Message{
Role: schema.User,
@@ -158,8 +187,12 @@ func (c *Chat) runPrompt(prompt string) error {
c.history = append(c.history, userMsg)
for {
ctx := context.Background()
spinner.New().Type(spinner.Dots).Title("Thinking...").Run()
resp, err := c.model.Generate(ctx, c.history)
var resp *schema.Message
var err error
action := func() {
resp, err = c.model.Generate(ctx, c.history)
}
_ = spinner.New().Title("Thinking...").Action(action).Run()
if err != nil {
return err
}
@@ -214,10 +247,11 @@ func (c *Chat) runPrompt(prompt string) error {
// Render and display response
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 {
fmt.Printf("\nAssistant: %s\n", resp.Content)
fmt.Printf("\n%s", errorStyle.Render("Assistant: "+resp.Content))
}
return nil
}
}
@@ -328,7 +362,9 @@ func (c *Chat) showTools() {
} else {
for _, tool := range serverTools.Tools {
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)
}
}
@@ -354,15 +390,6 @@ func loadSystemPrompt(filePath string) (string, error) {
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 {
width, _, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil {

View File

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