/* * Copyright 2026 CloudWeGo Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package main import ( "bufio" "context" "errors" "flag" "fmt" "io" "os" "strings" "github.com/google/uuid" "github.com/cloudwego/eino/adk" "github.com/cloudwego/eino/schema" examplemodel "github.com/cloudwego/eino-examples/adk/common/model" "github.com/cloudwego/eino-examples/quickstart/chatwitheino/mem" ) func main() { var sessionID string var instruction string flag.StringVar(&sessionID, "session", "", "session ID (creates new if empty)") flag.StringVar(&instruction, "instruction", "You are a helpful assistant.", "") flag.Parse() ctx := context.Background() cm := examplemodel.NewChatModel() agent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{ Name: "Ch03MemoryAgent", Description: "ChatModelAgent with JSONL-based persistent session.", Instruction: instruction, Model: cm, }) if err != nil { _, _ = fmt.Fprintln(os.Stderr, err) os.Exit(1) } runner := adk.NewRunner(ctx, adk.RunnerConfig{ Agent: agent, EnableStreaming: true, }) sessionDir := os.Getenv("SESSION_DIR") if sessionDir == "" { sessionDir = "./data/sessions" } store, err := mem.NewStore(sessionDir) if err != nil { _, _ = fmt.Fprintln(os.Stderr, err) os.Exit(1) } if sessionID == "" { sessionID = uuid.New().String() fmt.Printf("Created new session: %s\n", sessionID) } else { fmt.Printf("Resuming session: %s\n", sessionID) } session, err := store.GetOrCreate(sessionID) if err != nil { _, _ = fmt.Fprintln(os.Stderr, err) os.Exit(1) } fmt.Printf("Session title: %s\n", session.Title()) fmt.Println("Enter your message (empty line to exit):") scanner := bufio.NewScanner(os.Stdin) for { _, _ = fmt.Fprint(os.Stdout, "you> ") if !scanner.Scan() { break } line := strings.TrimSpace(scanner.Text()) if line == "" { break } userMsg := schema.UserMessage(line) if err := session.Append(userMsg); err != nil { _, _ = fmt.Fprintln(os.Stderr, err) os.Exit(1) } history := session.GetMessages() events := runner.Run(ctx, history) content, err := printAndCollectAssistantFromEvents(events) if err != nil { _, _ = fmt.Fprintln(os.Stderr, err) os.Exit(1) } assistantMsg := schema.AssistantMessage(content, nil) if err := session.Append(assistantMsg); err != nil { _, _ = fmt.Fprintln(os.Stderr, err) os.Exit(1) } } if err := scanner.Err(); err != nil { _, _ = fmt.Fprintln(os.Stderr, err) os.Exit(1) } fmt.Printf("\nSession saved: %s\n", sessionID) fmt.Printf("Resume with: go run ./cmd/ch03 --session %s\n", sessionID) } func printAndCollectAssistantFromEvents(events *adk.AsyncIterator[*adk.AgentEvent]) (string, error) { var sb strings.Builder for { event, ok := events.Next() if !ok { break } if event.Err != nil { return "", event.Err } if event.Output == nil || event.Output.MessageOutput == nil { continue } mv := event.Output.MessageOutput if mv.Role != schema.Assistant { continue } if mv.IsStreaming { mv.MessageStream.SetAutomaticClose() for { frame, err := mv.MessageStream.Recv() if errors.Is(err, io.EOF) { break } if err != nil { return "", err } if frame != nil && frame.Content != "" { sb.WriteString(frame.Content) _, _ = fmt.Fprint(os.Stdout, frame.Content) } } _, _ = fmt.Fprintln(os.Stdout) continue } if mv.Message != nil { sb.WriteString(mv.Message.Content) _, _ = fmt.Fprintln(os.Stdout, mv.Message.Content) } else { _, _ = fmt.Fprintln(os.Stdout) } } return sb.String(), nil }