package main import ( "bufio" "context" "fmt" "os" "strings" ) const systemPrompt = `You are a coding assistant running inside a CLI. You have file tools scoped to the current project directory. All paths are relative to the project root; absolute paths and paths that escape the root (via "..") will be rejected. Prefer listing and reading before editing. Keep replies concise.` func main() { root, err := os.Getwd() if err != nil { fmt.Fprintln(os.Stderr, "error getting working directory:", err) os.Exit(1) } if err := loadConfig(root); err != nil { fmt.Fprintln(os.Stderr, "config error:", err) os.Exit(1) } apiKey := os.Getenv("OPENAI_API_KEY") baseURL := getEnvDefault("OPENAI_BASE_URL", "https://api.openai.com/v1") model := getEnvDefault("OPENAI_MODEL", "gpt-4o-mini") if apiKey == "" { fmt.Fprintln(os.Stderr, "OPENAI_API_KEY is not set") os.Exit(1) } client := NewClient(baseURL, apiKey, model) tools := toolDefinitions() messages := []Message{{Role: "system", Content: systemPrompt}} fmt.Printf("NyxTex agent — model=%s root=%s\n", model, root) fmt.Println("Type your request. Empty line to submit. Ctrl+D or /exit to quit.") reader := bufio.NewReader(os.Stdin) for { fmt.Print("\n> ") input, err := readUserInput(reader) if err != nil { fmt.Println() return } input = strings.TrimSpace(input) if input == "" { continue } if input == "/exit" || input == "/quit" { return } messages = append(messages, Message{Role: "user", Content: input}) if err := runTurn(context.Background(), client, tools, root, &messages); err != nil { fmt.Fprintln(os.Stderr, "error:", err) } } } func readUserInput(r *bufio.Reader) (string, error) { line, err := r.ReadString('\n') if err != nil && line == "" { return "", err } return line, nil } // runTurn sends the conversation and handles any tool-call loop until the // assistant produces a plain text reply. func runTurn(ctx context.Context, client *Client, tools []Tool, root string, messages *[]Message) error { for { msg, err := client.Chat(ctx, *messages, tools) if err != nil { return err } *messages = append(*messages, msg) if len(msg.ToolCalls) == 0 { if strings.TrimSpace(msg.Content) != "" { fmt.Println(msg.Content) } return nil } for _, tc := range msg.ToolCalls { fmt.Printf(" [tool] %s %s\n", tc.Function.Name, tc.Function.Arguments) result := runTool(root, tc.Function.Name, tc.Function.Arguments) *messages = append(*messages, Message{ Role: "tool", ToolCallID: tc.ID, Name: tc.Function.Name, Content: result, }) } } } func getEnvDefault(key, def string) string { if v := os.Getenv(key); v != "" { return v } return def }