Compare commits
No commits in common. "01c90d587fc9113e4027cd5feb654e6a70a963ac" and "e4965f93686e63af6adcee15619c5bce5446944d" have entirely different histories.
01c90d587f
...
e4965f9368
7 changed files with 68 additions and 311 deletions
|
|
@ -1,4 +1,2 @@
|
||||||
ANTHROPIC_API_KEY=""
|
ANTHROPIC_API_KEY=""
|
||||||
SYSTEM_PROMPT=""
|
SYSTEM_PROMPT=""
|
||||||
KLOD_LOGS=false
|
|
||||||
KLOD_LOG_FILE=""
|
|
||||||
|
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1 @@
|
||||||
.env
|
.env
|
||||||
klod
|
|
||||||
|
|
|
||||||
48
README.md
48
README.md
|
|
@ -1,15 +1,14 @@
|
||||||
# Klod
|
# klod
|
||||||
|
|
||||||
Klod (pronounced \klod\\), a simple Go-based CLI tool for interacting with the Anthropic API
|
A simple, fast CLI tool for chatting with Claude using the Anthropic API with real-time streaming responses.
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
Sometimes you just need to quickly check/ask an LLM something. I basically live in the terminal so I want to avoid the context switch to a browser. Claude code on the other hand is a bit too eager to help (which has its benefits but no necessarily for your quick short messages). Therefore I quickly stiched together klod, originally in bash, still living as [./main.sh](main.sh) at the root of the project.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
- Interactive chat with Claude in your terminal
|
||||||
|
- Real-time streaming responses (see text as Claude types)
|
||||||
- Maintains conversation history within a session
|
- Maintains conversation history within a session
|
||||||
- Configurable model and system prompts
|
- Configurable model and system prompts
|
||||||
|
- Multi-location config file support
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
|
|
@ -19,21 +18,18 @@ Sometimes you just need to quickly check/ask an LLM something. I basically live
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Clone and build:
|
1. Clone and build:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/leoalho/klod.git
|
git clone <your-repo-url>
|
||||||
cd anthropic-cli
|
cd anthropic-cli
|
||||||
go build
|
go build -o klod
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Create a symlink for global access:
|
2. Create a symlink for global access:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo ln -s $(pwd)/klod /usr/local/bin/klod
|
sudo ln -s $(pwd)/klod /usr/local/bin/klod
|
||||||
```
|
```
|
||||||
|
|
||||||
Or install via Go:
|
Or install via Go:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go install
|
go install
|
||||||
```
|
```
|
||||||
|
|
@ -41,7 +37,6 @@ go install
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
The tool looks for configuration files in the following order:
|
The tool looks for configuration files in the following order:
|
||||||
|
|
||||||
1. `~/.config/klod/config` (XDG standard location)
|
1. `~/.config/klod/config` (XDG standard location)
|
||||||
2. `~/.klod.env` (home directory)
|
2. `~/.klod.env` (home directory)
|
||||||
3. `.env` in the current directory (for project-specific overrides)
|
3. `.env` in the current directory (for project-specific overrides)
|
||||||
|
|
@ -57,8 +52,6 @@ cat > ~/.config/klod/config << EOF
|
||||||
ANTHROPIC_API_KEY=your-api-key-here
|
ANTHROPIC_API_KEY=your-api-key-here
|
||||||
MODEL=claude-sonnet-4-5-20250929
|
MODEL=claude-sonnet-4-5-20250929
|
||||||
SYSTEM_PROMPT=
|
SYSTEM_PROMPT=
|
||||||
KLOD_LOGS=false
|
|
||||||
KLOD_LOG_FILE=
|
|
||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -67,37 +60,42 @@ EOF
|
||||||
- `ANTHROPIC_API_KEY` (required): Your Anthropic API key
|
- `ANTHROPIC_API_KEY` (required): Your Anthropic API key
|
||||||
- `MODEL` (optional): Model to use (default: claude-sonnet-4-5-20250929)
|
- `MODEL` (optional): Model to use (default: claude-sonnet-4-5-20250929)
|
||||||
- `SYSTEM_PROMPT` (optional): Custom system prompt for Claude
|
- `SYSTEM_PROMPT` (optional): Custom system prompt for Claude
|
||||||
- `KLOD_LOGS` (optional): Enable conversation logging (default: false, set to "true" or "1" to enable)
|
|
||||||
- `KLOD_LOG_FILE` (optional): Custom log file path (default: `$XDG_STATE_HOME/klod/conversations.log` or `~/.local/state/klod/conversations.log`)
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Start a conversation:
|
Start a conversation:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
klod Hello, how are you?
|
klod "Hello, how are you?"
|
||||||
```
|
```
|
||||||
|
|
||||||
This will:
|
This will:
|
||||||
|
|
||||||
1. Send your initial message to Claude
|
1. Send your initial message to Claude
|
||||||
2. Stream the response in real-time
|
2. Stream the response in real-time
|
||||||
3. Enter an interactive chat mode where you can continue the conversation
|
3. Enter an interactive chat mode where you can continue the conversation
|
||||||
|
|
||||||
Type `exit` or `quit` to end the conversation.
|
Type `exit` or `quit` to end the conversation.
|
||||||
|
|
||||||
You can also start without an initial prompt:
|
## Examples
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
klod
|
# Ask a quick question
|
||||||
```
|
klod "What is the capital of France?"
|
||||||
|
|
||||||
This starts the service and asks for your first prompt interactively.
|
# Start a coding session
|
||||||
|
klod "Help me write a Python function to calculate fibonacci numbers"
|
||||||
|
|
||||||
|
# Use a different model (set in config)
|
||||||
|
# Edit your config file and change MODEL=claude-opus-4-5-20251101
|
||||||
|
klod "Explain quantum computing"
|
||||||
|
```
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
Run without building:
|
Run without building:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go run main.go your message here
|
go run main.go "your message here"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
|
||||||
7
go.mod
7
go.mod
|
|
@ -2,9 +2,4 @@ module klod
|
||||||
|
|
||||||
go 1.21
|
go 1.21
|
||||||
|
|
||||||
require (
|
require github.com/joho/godotenv v1.5.1
|
||||||
github.com/joho/godotenv v1.5.1
|
|
||||||
golang.org/x/term v0.27.0
|
|
||||||
)
|
|
||||||
|
|
||||||
require golang.org/x/sys v0.28.0 // indirect
|
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -1,6 +1,2 @@
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
|
||||||
|
|
|
||||||
255
main.go
255
main.go
|
|
@ -10,12 +10,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"golang.org/x/term"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
|
|
@ -61,189 +57,6 @@ type StreamError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var conversationHistory []Message
|
var conversationHistory []Message
|
||||||
var loggingEnabled bool
|
|
||||||
var logFilePath string
|
|
||||||
|
|
||||||
type winsize struct {
|
|
||||||
Row uint16
|
|
||||||
Col uint16
|
|
||||||
Xpixel uint16
|
|
||||||
Ypixel uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTerminalWidth() int {
|
|
||||||
ws := &winsize{}
|
|
||||||
retCode, _, _ := syscall.Syscall(syscall.SYS_IOCTL,
|
|
||||||
uintptr(syscall.Stdin),
|
|
||||||
uintptr(syscall.TIOCGWINSZ),
|
|
||||||
uintptr(unsafe.Pointer(ws)))
|
|
||||||
|
|
||||||
if int(retCode) == -1 {
|
|
||||||
return 80 // Default fallback
|
|
||||||
}
|
|
||||||
return int(ws.Col)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printSeparator() {
|
|
||||||
width := getTerminalWidth()
|
|
||||||
fmt.Println(strings.Repeat("─", width))
|
|
||||||
}
|
|
||||||
|
|
||||||
func logConversation(message Message) error {
|
|
||||||
if !loggingEnabled {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure log directory exists
|
|
||||||
logDir := filepath.Dir(logFilePath)
|
|
||||||
if err := os.MkdirAll(logDir, 0755); err != nil {
|
|
||||||
return fmt.Errorf("failed to create log directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open log file in append mode
|
|
||||||
file, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to open log file: %w", err)
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
// Write timestamp and message
|
|
||||||
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
|
||||||
logEntry := fmt.Sprintf("[%s] %s: %s\n", timestamp, strings.ToUpper(message.Role), message.Content)
|
|
||||||
|
|
||||||
if _, err := file.WriteString(logEntry); err != nil {
|
|
||||||
return fmt.Errorf("failed to write to log file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// enableBracketedPaste sends escape sequence to enable bracketed paste mode
|
|
||||||
func enableBracketedPaste() {
|
|
||||||
fmt.Print("\033[?2004h")
|
|
||||||
}
|
|
||||||
|
|
||||||
// disableBracketedPaste sends escape sequence to disable bracketed paste mode
|
|
||||||
func disableBracketedPaste() {
|
|
||||||
fmt.Print("\033[?2004l")
|
|
||||||
}
|
|
||||||
|
|
||||||
// readInputWithPasteSupport reads user input with support for multi-line paste
|
|
||||||
// It uses raw terminal mode to detect bracketed paste sequences
|
|
||||||
func readInputWithPasteSupport() (string, error) {
|
|
||||||
fd := int(os.Stdin.Fd())
|
|
||||||
|
|
||||||
// Check if stdin is a terminal
|
|
||||||
if !term.IsTerminal(fd) {
|
|
||||||
// Fall back to simple readline for non-terminal input
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
|
||||||
line, err := reader.ReadString('\n')
|
|
||||||
return strings.TrimSpace(line), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save terminal state and switch to raw mode
|
|
||||||
oldState, err := term.MakeRaw(fd)
|
|
||||||
if err != nil {
|
|
||||||
// Fall back to simple readline if raw mode fails
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
|
||||||
line, err := reader.ReadString('\n')
|
|
||||||
return strings.TrimSpace(line), err
|
|
||||||
}
|
|
||||||
defer term.Restore(fd, oldState)
|
|
||||||
|
|
||||||
var input strings.Builder
|
|
||||||
var buf [1]byte
|
|
||||||
inPaste := false
|
|
||||||
escBuf := make([]byte, 0, 10)
|
|
||||||
|
|
||||||
for {
|
|
||||||
n, err := os.Stdin.Read(buf[:])
|
|
||||||
if err != nil || n == 0 {
|
|
||||||
return input.String(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
b := buf[0]
|
|
||||||
|
|
||||||
// Handle escape sequences
|
|
||||||
if b == 0x1b { // ESC
|
|
||||||
escBuf = append(escBuf[:0], b)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(escBuf) > 0 {
|
|
||||||
escBuf = append(escBuf, b)
|
|
||||||
|
|
||||||
// Check for bracketed paste start: ESC[200~
|
|
||||||
if len(escBuf) == 6 && escBuf[0] == 0x1b && escBuf[1] == '[' &&
|
|
||||||
escBuf[2] == '2' && escBuf[3] == '0' && escBuf[4] == '0' && escBuf[5] == '~' {
|
|
||||||
inPaste = true
|
|
||||||
escBuf = escBuf[:0]
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for bracketed paste end: ESC[201~
|
|
||||||
if len(escBuf) == 6 && escBuf[0] == 0x1b && escBuf[1] == '[' &&
|
|
||||||
escBuf[2] == '2' && escBuf[3] == '0' && escBuf[4] == '1' && escBuf[5] == '~' {
|
|
||||||
inPaste = false
|
|
||||||
escBuf = escBuf[:0]
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If sequence is getting too long without matching, it's not a paste sequence
|
|
||||||
// Write accumulated bytes and reset
|
|
||||||
if len(escBuf) > 6 {
|
|
||||||
for _, eb := range escBuf {
|
|
||||||
if eb >= 0x20 {
|
|
||||||
input.WriteByte(eb)
|
|
||||||
fmt.Print(string(eb))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
escBuf = escBuf[:0]
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle special keys
|
|
||||||
switch b {
|
|
||||||
case '\r', '\n': // Enter
|
|
||||||
if inPaste {
|
|
||||||
input.WriteByte('\n')
|
|
||||||
fmt.Print("\r\n") // Echo newline
|
|
||||||
} else {
|
|
||||||
fmt.Print("\r\n")
|
|
||||||
return input.String(), nil
|
|
||||||
}
|
|
||||||
case 0x03: // Ctrl+C
|
|
||||||
fmt.Print("^C\r\n")
|
|
||||||
return "", fmt.Errorf("interrupted")
|
|
||||||
case 0x04: // Ctrl+D
|
|
||||||
if input.Len() == 0 {
|
|
||||||
return "", io.EOF
|
|
||||||
}
|
|
||||||
return input.String(), nil
|
|
||||||
case 0x7f, 0x08: // Backspace/Delete
|
|
||||||
s := input.String()
|
|
||||||
if len(s) > 0 {
|
|
||||||
// Handle multi-byte UTF-8 characters
|
|
||||||
runes := []rune(s)
|
|
||||||
if len(runes) > 0 {
|
|
||||||
input.Reset()
|
|
||||||
input.WriteString(string(runes[:len(runes)-1]))
|
|
||||||
fmt.Print("\b \b") // Erase character on screen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if b >= 0x20 || b == '\t' { // Printable character or tab
|
|
||||||
input.WriteByte(b)
|
|
||||||
if b == '\t' {
|
|
||||||
fmt.Print(" ") // Display tab as spaces
|
|
||||||
} else {
|
|
||||||
fmt.Print(string(b)) // Echo character
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadConfig() error {
|
func loadConfig() error {
|
||||||
// Try loading config from multiple locations in order
|
// Try loading config from multiple locations in order
|
||||||
|
|
@ -291,104 +104,70 @@ func main() {
|
||||||
|
|
||||||
systemPrompt := os.Getenv("SYSTEM_PROMPT")
|
systemPrompt := os.Getenv("SYSTEM_PROMPT")
|
||||||
|
|
||||||
// Configure logging
|
// Get initial prompt from command-line arguments
|
||||||
loggingEnabled = os.Getenv("KLOD_LOGS") == "true" || os.Getenv("KLOD_LOGS") == "1"
|
if len(os.Args) < 2 {
|
||||||
logFilePath = os.Getenv("KLOD_LOG_FILE")
|
fmt.Fprintln(os.Stderr, "Usage: klod <your prompt>")
|
||||||
if logFilePath == "" {
|
os.Exit(1)
|
||||||
// Use XDG_STATE_HOME or default to ~/.local/state per XDG spec
|
|
||||||
stateDir := os.Getenv("XDG_STATE_HOME")
|
|
||||||
if stateDir == "" {
|
|
||||||
homeDir, _ := os.UserHomeDir()
|
|
||||||
stateDir = filepath.Join(homeDir, ".local", "state")
|
|
||||||
}
|
|
||||||
// Create a unique log file for this session based on timestamp
|
|
||||||
sessionTime := time.Now().Format("2006-01-02_15-04-05")
|
|
||||||
logFilePath = filepath.Join(stateDir, "klod", "sessions", sessionTime+".log")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get initial prompt from command-line arguments (if provided)
|
|
||||||
if len(os.Args) >= 2 {
|
|
||||||
initialPrompt := strings.Join(os.Args[1:], " ")
|
initialPrompt := strings.Join(os.Args[1:], " ")
|
||||||
|
|
||||||
// Add initial user message to conversation history
|
// Add initial user message to conversation history
|
||||||
userMsg := Message{
|
conversationHistory = append(conversationHistory, Message{
|
||||||
Role: "user",
|
Role: "user",
|
||||||
Content: initialPrompt,
|
Content: initialPrompt,
|
||||||
}
|
})
|
||||||
conversationHistory = append(conversationHistory, userMsg)
|
|
||||||
logConversation(userMsg)
|
|
||||||
|
|
||||||
// Send initial message
|
// Send initial message
|
||||||
printSeparator()
|
|
||||||
fmt.Print("\033[34mAssistant: \033[0m")
|
|
||||||
response, err := sendMessage(apiKey, model, systemPrompt)
|
response, err := sendMessage(apiKey, model, systemPrompt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
printSeparator()
|
|
||||||
|
|
||||||
// Add assistant's response to conversation history
|
// Add assistant's response to conversation history
|
||||||
assistantMsg := Message{
|
conversationHistory = append(conversationHistory, Message{
|
||||||
Role: "assistant",
|
Role: "assistant",
|
||||||
Content: response,
|
Content: response,
|
||||||
}
|
})
|
||||||
conversationHistory = append(conversationHistory, assistantMsg)
|
|
||||||
logConversation(assistantMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interactive conversation loop with bracketed paste support
|
|
||||||
enableBracketedPaste()
|
|
||||||
defer disableBracketedPaste()
|
|
||||||
|
|
||||||
|
// Interactive conversation loop
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
for {
|
for {
|
||||||
|
fmt.Println()
|
||||||
fmt.Print("\033[32mYou (or 'exit' to quit): \033[0m")
|
fmt.Print("\033[32mYou (or 'exit' to quit): \033[0m")
|
||||||
|
|
||||||
userInput, err := readInputWithPasteSupport()
|
userInput, err := reader.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
|
||||||
fmt.Println("\nGoodbye!")
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
userInput = strings.TrimSpace(userInput)
|
userInput = strings.TrimSpace(userInput)
|
||||||
|
|
||||||
// Check if user wants to exit
|
// Check if user wants to exit
|
||||||
if userInput == "exit" || userInput == "quit" {
|
if userInput == "exit" || userInput == "quit" || userInput == "" {
|
||||||
fmt.Println("Goodbye!")
|
fmt.Println("Goodbye!")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if userInput == "" {
|
|
||||||
fmt.Println("Please enter a prompt (or type 'exit' to quit).")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add user input to conversation history
|
// Add user input to conversation history
|
||||||
userMsg := Message{
|
conversationHistory = append(conversationHistory, Message{
|
||||||
Role: "user",
|
Role: "user",
|
||||||
Content: userInput,
|
Content: userInput,
|
||||||
}
|
})
|
||||||
conversationHistory = append(conversationHistory, userMsg)
|
|
||||||
logConversation(userMsg)
|
|
||||||
|
|
||||||
// Send message and get response
|
// Send message and get response
|
||||||
printSeparator()
|
|
||||||
fmt.Print("\033[34mAssistant: \033[0m")
|
|
||||||
response, err := sendMessage(apiKey, model, systemPrompt)
|
response, err := sendMessage(apiKey, model, systemPrompt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
printSeparator()
|
|
||||||
|
|
||||||
// Add assistant's response to conversation history
|
// Add assistant's response to conversation history
|
||||||
assistantMsg := Message{
|
conversationHistory = append(conversationHistory, Message{
|
||||||
Role: "assistant",
|
Role: "assistant",
|
||||||
Content: response,
|
Content: response,
|
||||||
}
|
})
|
||||||
conversationHistory = append(conversationHistory, assistantMsg)
|
|
||||||
logConversation(assistantMsg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
18
main.sh
18
main.sh
|
|
@ -78,15 +78,11 @@ send_message() {
|
||||||
CONVERSATION_HISTORY+=("$response")
|
CONVERSATION_HISTORY+=("$response")
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ -n "$PROMPT" ]]; then
|
# Add initial user prompt to conversation history
|
||||||
# Add initial user prompt to conversation history
|
CONVERSATION_HISTORY+=("$PROMPT")
|
||||||
CONVERSATION_HISTORY+=("$PROMPT")
|
|
||||||
|
|
||||||
# Send initial message
|
# Send initial message
|
||||||
send_message
|
send_message
|
||||||
else
|
|
||||||
:
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Conversation loop
|
# Conversation loop
|
||||||
while true; do
|
while true; do
|
||||||
|
|
@ -95,14 +91,10 @@ while true; do
|
||||||
read -e user_input
|
read -e user_input
|
||||||
|
|
||||||
# Check if user wants to exit
|
# Check if user wants to exit
|
||||||
if [[ "$user_input" == "exit" ]] || [[ "$user_input" == "quit" ]]; then
|
if [[ "$user_input" == "exit" ]] || [[ "$user_input" == "quit" ]] || [[ -z "$user_input" ]]; then
|
||||||
echo "Goodbye!"
|
echo "Goodbye!"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
if [[ -z "$user_input" ]]; then
|
|
||||||
echo "Please enter a prompt (or type 'exit' to quit)."
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add user input to conversation history
|
# Add user input to conversation history
|
||||||
CONVERSATION_HISTORY+=("$user_input")
|
CONVERSATION_HISTORY+=("$user_input")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue