Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions chat/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package chat
import (
"context"
"strings"

"github.com/x2d7/interlude/chat/tools"
)

func (c *Chat) Complete(ctx context.Context, client Client) <-chan StreamEvent {
Expand Down Expand Up @@ -69,7 +71,20 @@ func (s *sessionState) flushLastToolCall() bool {
return ok
}

func (c *Chat) ensureDefaults() {
if c.Messages == nil {
c.Messages = NewMessages()
}
if c.Tools == nil {
t := tools.NewTools()
c.Tools = &t
}
}

func (c *Chat) Session(ctx context.Context, client Client) <-chan StreamEvent {
// ensuring default values
c.ensureDefaults()

// insert chat context into client input configuration
client = client.SyncInput(c)

Expand Down
109 changes: 109 additions & 0 deletions chat/chat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1416,3 +1416,112 @@ func TestSession_MixedTokensAndToolCalls(t *testing.T) {
t.Errorf("Expected 2 tool calls in history, got %d", toolCallsInHistory)
}
}

// ==================== ensureDefaults Tests ====================

// TestEnsureDefaults_MessagesNil tests that Messages is initialized when nil
func TestEnsureDefaults_MessagesNil(t *testing.T) {
tools := tools.NewTools()
chat := &Chat{
Messages: nil,
Tools: &tools,
}

chat.ensureDefaults()

if chat.Messages == nil {
t.Error("Messages should not be nil after ensureDefaults")
}

// Verify Messages is usable
messages := chat.Messages.Snapshot()
if len(messages) != 0 {
t.Errorf("Expected empty messages, got %d", len(messages))
}
}

// TestEnsureDefaults_ToolsNil tests that Tools is initialized when nil
func TestEnsureDefaults_ToolsNil(t *testing.T) {
chat := &Chat{
Messages: NewMessages(),
Tools: nil,
}

chat.ensureDefaults()

if chat.Tools == nil {
t.Error("Tools should not be nil after ensureDefaults")
}

// Verify Tools is usable (empty slice, not nil)
toolList := chat.Tools.Snapshot()
if len(toolList) != 0 {
t.Errorf("Expected empty tools, got %d", len(toolList))
}
}

// TestEnsureDefaults_BothNil tests that both Messages and Tools are initialized when both are nil
func TestEnsureDefaults_BothNil(t *testing.T) {
chat := &Chat{
Messages: nil,
Tools: nil,
}

chat.ensureDefaults()

if chat.Messages == nil {
t.Error("Messages should not be nil after ensureDefaults")
}

if chat.Tools == nil {
t.Error("Tools should not be nil after ensureDefaults")
}
}

// TestEnsureDefaults_AlreadySet tests that existing values are not overwritten
func TestEnsureDefaults_AlreadySet(t *testing.T) {
// Setup chat with existing messages and tools
ts := tools.NewTools()
chat := &Chat{
Messages: NewMessages(),
Tools: &ts, // Use NewTools() to properly initialize
}

// Add some data
chat.AddMessage(SenderUser{}, "test message")
tool, err := tools.NewTool("test-tool", "Test tool",
func(input map[string]string) (string, error) {
return "result", nil
})
if err != nil {
t.Fatalf("Failed to create tool: %v", err)
}
chat.Tools.Add(tool)

// Get pointers to verify they're not replaced
messagesBefore := chat.Messages
toolsBefore := chat.Tools

// Call ensureDefaults
chat.ensureDefaults()

// Verify same instances are preserved
if chat.Messages != messagesBefore {
t.Error("Messages should not be replaced when already set")
}

if chat.Tools != toolsBefore {
t.Error("Tools should not be replaced when already set")
}

// Verify data is still intact
messages := chat.Messages.Snapshot()
if len(messages) != 1 {
t.Errorf("Expected 1 message, got %d", len(messages))
}

toolList := chat.Tools.Snapshot()
if len(toolList) != 1 {
t.Errorf("Expected 1 tool, got %d", len(toolList))
}
}