Files
Enterprise-Knowledge-Base/client/cmd/agent_test/main.go
T

370 lines
11 KiB
Go

package main
import (
"bufio"
"context"
"flag"
"fmt"
"os"
"strings"
"time"
"github.com/Tencent/WeKnora/client"
)
// Colors for terminal output
const (
ColorReset = "\033[0m"
ColorRed = "\033[31m"
ColorGreen = "\033[32m"
ColorYellow = "\033[33m"
ColorBlue = "\033[34m"
ColorMagenta = "\033[35m"
ColorCyan = "\033[36m"
ColorWhite = "\033[37m"
ColorBold = "\033[1m"
)
// Config holds the configuration
type Config struct {
BaseURL string
Token string
KnowledgeBaseID string
}
// CLI represents the command line interface
type CLI struct {
client *client.Client
config *Config
currentSessionID string
agentSession *client.AgentSession
}
func main() {
baseURL := flag.String("url", "http://localhost:8080", "WeKnora API base URL")
token := flag.String("token", "", "API authentication token")
kbID := flag.String("kb", "", "Knowledge base ID")
sessionID := flag.String("session", "", "Existing session ID (optional)")
flag.Parse()
config := &Config{
BaseURL: *baseURL,
Token: *token,
KnowledgeBaseID: *kbID,
}
cli := NewCLI(config)
// Use existing session if provided
if *sessionID != "" {
cli.currentSessionID = *sessionID
cli.agentSession = cli.client.NewAgentSession(*sessionID)
fmt.Printf("%s✓ Using existing session: %s%s\n\n", ColorGreen, *sessionID, ColorReset)
}
cli.Run()
}
// NewCLI creates a new CLI instance
func NewCLI(config *Config) *CLI {
clientOptions := []client.ClientOption{
client.WithTimeout(120 * time.Second),
}
if config.Token != "" {
clientOptions = append(clientOptions, client.WithToken(config.Token))
}
return &CLI{
client: client.NewClient(config.BaseURL, clientOptions...),
config: config,
}
}
// Run starts the interactive CLI
func (cli *CLI) Run() {
cli.printWelcome()
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print(cli.getPrompt())
input, err := reader.ReadString('\n')
if err != nil {
fmt.Printf("%sError reading input: %v%s\n", ColorRed, err, ColorReset)
continue
}
input = strings.TrimSpace(input)
if input == "" {
continue
}
if !cli.handleCommand(input) {
break
}
}
fmt.Printf("\n%sGoodbye!%s\n", ColorCyan, ColorReset)
}
func (cli *CLI) getPrompt() string {
if cli.currentSessionID != "" {
return fmt.Sprintf("%s[Session: %s]%s > ", ColorBlue, cli.currentSessionID[:8], ColorReset)
}
return fmt.Sprintf("%s[No Session]%s > ", ColorYellow, ColorReset)
}
func (cli *CLI) printWelcome() {
fmt.Printf("\n%s╔════════════════════════════════════════════════════════════╗%s\n", ColorCyan, ColorReset)
fmt.Printf("%s║ WeKnora Agent QA Testing Tool ║%s\n", ColorCyan, ColorReset)
fmt.Printf("%s╚════════════════════════════════════════════════════════════╝%s\n\n", ColorCyan, ColorReset)
fmt.Printf("%sAvailable commands:%s\n", ColorBold, ColorReset)
fmt.Printf(" %snew%s - Create a new session\n", ColorGreen, ColorReset)
fmt.Printf(" %sask <query>%s - Ask agent a question\n", ColorGreen, ColorReset)
fmt.Printf(" %sinfo%s - Show current session info\n", ColorGreen, ColorReset)
fmt.Printf(" %ssessions%s - List all sessions\n", ColorGreen, ColorReset)
fmt.Printf(" %sswitch <id>%s - Switch to another session\n", ColorGreen, ColorReset)
fmt.Printf(" %shelp%s - Show this help message\n", ColorGreen, ColorReset)
fmt.Printf(" %sexit/quit%s - Exit the program\n\n", ColorGreen, ColorReset)
}
func (cli *CLI) handleCommand(input string) bool {
parts := strings.SplitN(input, " ", 2)
command := strings.ToLower(parts[0])
switch command {
case "help":
cli.printWelcome()
case "new":
cli.createNewSession()
case "ask":
if len(parts) < 2 {
fmt.Printf("%sUsage: ask <your question>%s\n", ColorRed, ColorReset)
return true
}
cli.askQuestion(parts[1])
case "info":
cli.showSessionInfo()
case "sessions":
cli.listSessions()
case "switch":
if len(parts) < 2 {
fmt.Printf("%sUsage: switch <session_id>%s\n", ColorRed, ColorReset)
return true
}
cli.switchSession(parts[1])
case "exit", "quit":
return false
default:
fmt.Printf("%sUnknown command: %s. Type 'help' for available commands.%s\n", ColorRed, command, ColorReset)
}
return true
}
func (cli *CLI) createNewSession() {
if cli.config.KnowledgeBaseID == "" {
fmt.Printf("%sError: Knowledge base ID is required. Use -kb flag.%s\n", ColorRed, ColorReset)
return
}
fmt.Printf("%sCreating new session...%s\n", ColorYellow, ColorReset)
ctx := context.Background()
request := &client.CreateSessionRequest{
KnowledgeBaseID: cli.config.KnowledgeBaseID,
SessionStrategy: &client.SessionStrategy{
MaxRounds: 10,
EnableRewrite: false,
FallbackStrategy: "default",
EmbeddingTopK: 10,
},
}
session, err := cli.client.CreateSession(ctx, request)
if err != nil {
fmt.Printf("%s✗ Failed to create session: %v%s\n", ColorRed, err, ColorReset)
return
}
cli.currentSessionID = session.ID
cli.agentSession = cli.client.NewAgentSession(session.ID)
fmt.Printf("%s✓ Session created successfully!%s\n", ColorGreen, ColorReset)
fmt.Printf(" Session ID: %s%s%s\n", ColorCyan, session.ID, ColorReset)
fmt.Printf(" Knowledge Base: %s%s%s\n", ColorCyan, session.KnowledgeBaseID, ColorReset)
fmt.Printf(" Created At: %s%s%s\n\n", ColorCyan, session.CreatedAt, ColorReset)
}
func (cli *CLI) askQuestion(query string) {
if cli.agentSession == nil {
fmt.Printf("%sError: No active session. Create one with 'new' command.%s\n", ColorRed, ColorReset)
return
}
fmt.Printf("\n%s╔═══ Agent Processing ═══╗%s\n", ColorCyan, ColorReset)
fmt.Printf("%sQuery: %s%s%s\n\n", ColorBold, ColorWhite, query, ColorReset)
ctx := context.Background()
var (
thinkingContent string
finalAnswer string
references []*client.SearchResult
toolCalls []string
reflections []string
)
startTime := time.Now()
err := cli.agentSession.Ask(ctx, query, func(resp *client.AgentStreamResponse) error {
switch resp.ResponseType {
case client.AgentResponseTypeThinking:
thinkingContent += resp.Content
if resp.Done {
fmt.Printf("%s💭 Thinking:%s %s\n\n", ColorYellow, ColorReset, thinkingContent)
thinkingContent = ""
}
case client.AgentResponseTypeToolCall:
toolName := "Unknown"
if resp.Data != nil {
if name, ok := resp.Data["tool_name"].(string); ok {
toolName = name
}
}
toolCalls = append(toolCalls, toolName)
fmt.Printf("%s🔧 Tool Call:%s %s\n", ColorMagenta, ColorReset, toolName)
if resp.Data != nil {
if args, ok := resp.Data["arguments"]; ok {
fmt.Printf(" Arguments: %v\n", args)
}
}
case client.AgentResponseTypeToolResult:
fmt.Printf("%s✓ Tool Result:%s\n", ColorGreen, ColorReset)
fmt.Printf(" %s\n\n", resp.Content)
case client.AgentResponseTypeReferences:
if resp.KnowledgeReferences != nil {
references = append(references, resp.KnowledgeReferences...)
fmt.Printf("%s📚 Knowledge References:%s Found %d reference(s)\n", ColorCyan, ColorReset, len(resp.KnowledgeReferences))
for i, ref := range resp.KnowledgeReferences {
fmt.Printf(" %d. [Score: %.3f] %s\n", i+1, ref.Score, truncateString(ref.Content, 80))
fmt.Printf(" Knowledge: %s (Chunk: %d)\n", ref.KnowledgeTitle, ref.ChunkIndex)
}
fmt.Println()
}
case client.AgentResponseTypeAnswer:
finalAnswer += resp.Content
if resp.Done {
fmt.Printf("%s📝 Final Answer:%s\n", ColorGreen, ColorReset)
fmt.Printf("%s\n\n", finalAnswer)
}
case client.AgentResponseTypeReflection:
if resp.Done && resp.Content != "" {
reflections = append(reflections, resp.Content)
fmt.Printf("%s🤔 Reflection:%s %s\n\n", ColorBlue, ColorReset, resp.Content)
}
case client.AgentResponseTypeError:
fmt.Printf("%s✗ Error:%s %s\n\n", ColorRed, ColorReset, resp.Content)
}
return nil
})
if err != nil {
fmt.Printf("%s✗ Agent QA failed: %v%s\n", ColorRed, err, ColorReset)
return
}
duration := time.Since(startTime)
// Print summary
fmt.Printf("%s╔═══ Summary ═══╗%s\n", ColorCyan, ColorReset)
fmt.Printf("Duration: %s%.2fs%s\n", ColorCyan, duration.Seconds(), ColorReset)
fmt.Printf("Tool Calls: %s%d%s", ColorCyan, len(toolCalls), ColorReset)
if len(toolCalls) > 0 {
fmt.Printf(" (%s)", strings.Join(toolCalls, ", "))
}
fmt.Println()
fmt.Printf("References: %s%d%s\n", ColorCyan, len(references), ColorReset)
fmt.Printf("Reflections: %s%d%s\n", ColorCyan, len(reflections), ColorReset)
fmt.Printf("%s╚═══════════════╝%s\n\n", ColorCyan, ColorReset)
}
func (cli *CLI) showSessionInfo() {
if cli.currentSessionID == "" {
fmt.Printf("%sNo active session.%s\n", ColorYellow, ColorReset)
return
}
ctx := context.Background()
session, err := cli.client.GetSession(ctx, cli.currentSessionID)
if err != nil {
fmt.Printf("%s✗ Failed to get session info: %v%s\n", ColorRed, err, ColorReset)
return
}
fmt.Printf("\n%s╔═══ Session Information ═══╗%s\n", ColorCyan, ColorReset)
fmt.Printf("Session ID: %s%s%s\n", ColorWhite, session.ID, ColorReset)
fmt.Printf("Title: %s%s%s\n", ColorWhite, session.Title, ColorReset)
fmt.Printf("Knowledge Base ID: %s%s%s\n", ColorWhite, session.KnowledgeBaseID, ColorReset)
fmt.Printf("Max Rounds: %s%d%s\n", ColorWhite, session.MaxRounds, ColorReset)
fmt.Printf("Enable Rewrite: %s%v%s\n", ColorWhite, session.EnableRewrite, ColorReset)
fmt.Printf("Summary Model: %s%s%s\n", ColorWhite, session.SummaryModelID, ColorReset)
fmt.Printf("Created At: %s%s%s\n", ColorWhite, session.CreatedAt, ColorReset)
fmt.Printf("Updated At: %s%s%s\n", ColorWhite, session.UpdatedAt, ColorReset)
fmt.Printf("%s╚═══════════════════════════╝%s\n\n", ColorCyan, ColorReset)
}
func (cli *CLI) listSessions() {
ctx := context.Background()
sessions, total, err := cli.client.GetSessionsByTenant(ctx, 1, 10)
if err != nil {
fmt.Printf("%s✗ Failed to list sessions: %v%s\n", ColorRed, err, ColorReset)
return
}
fmt.Printf("\n%s╔═══ Sessions (Total: %d) ═══╗%s\n", ColorCyan, total, ColorReset)
for i, session := range sessions {
marker := " "
if session.ID == cli.currentSessionID {
marker = "►"
}
fmt.Printf("%s%s %d. %s%s\n", ColorGreen, marker, i+1, session.ID, ColorReset)
fmt.Printf(" Title: %s\n", session.Title)
fmt.Printf(" KB: %s\n", session.KnowledgeBaseID)
fmt.Printf(" Created: %s\n", session.CreatedAt)
fmt.Println()
}
fmt.Printf("%s╚════════════════════════════╝%s\n\n", ColorCyan, ColorReset)
}
func (cli *CLI) switchSession(sessionID string) {
ctx := context.Background()
session, err := cli.client.GetSession(ctx, sessionID)
if err != nil {
fmt.Printf("%s✗ Failed to switch session: %v%s\n", ColorRed, err, ColorReset)
return
}
cli.currentSessionID = session.ID
cli.agentSession = cli.client.NewAgentSession(session.ID)
fmt.Printf("%s✓ Switched to session: %s%s\n", ColorGreen, session.ID, ColorReset)
}
func truncateString(s string, maxLen int) string {
s = strings.ReplaceAll(s, "\n", " ")
if len(s) <= maxLen {
return s
}
return s[:maxLen] + "..."
}