on main help sign in
fix: improve lazy slice
6975271Carlos Alexandro Becker
internal/csync/slices.go+5−7
@@ -8,28 +8,26 @@ import (
8// LazySlice is a thread-safe lazy-loaded slice.
8// LazySlice is a thread-safe lazy-loaded slice.
9type LazySlice[K any] struct {
9type LazySlice[K any] struct {
10 inner []K
10 inner []K
11− mu sync.Mutex
11+ wg sync.WaitGroup
12}
12}
13
13
14// NewLazySlice creates a new slice and runs the [load] function in a goroutine
14// NewLazySlice creates a new slice and runs the [load] function in a goroutine
15// to populate it.
15// to populate it.
16func NewLazySlice[K any](load func() []K) *LazySlice[K] {
16func NewLazySlice[K any](load func() []K) *LazySlice[K] {
17 s := &LazySlice[K]{}
17 s := &LazySlice[K]{}
18− s.mu.Lock()
18+ s.wg.Add(1)
19 go func() {
19 go func() {
20 s.inner = load()
20 s.inner = load()
21− s.mu.Unlock()
21+ s.wg.Done()
22 }()
22 }()
23 return s
23 return s
24}
24}
25
25
26// Seq returns an iterator that yields elements from the slice.
26// Seq returns an iterator that yields elements from the slice.
27func (s *LazySlice[K]) Seq() iter.Seq[K] {
27func (s *LazySlice[K]) Seq() iter.Seq[K] {
28− s.mu.Lock()
28+ s.wg.Wait()
29− inner := s.inner
30− s.mu.Unlock()
31 return func(yield func(K) bool) {
29 return func(yield func(K) bool) {
32− for _, v := range inner {
30+ for _, v := range s.inner {
33 if !yield(v) {
31 if !yield(v) {
34 return
32 return
35 }
33 }
internal/llm/agent/agent.go+2−2
@@ -292,7 +292,7 @@ func (a *agent) generateTitle(ctx context.Context, sessionID string, content str
292 Parts: parts,
292 Parts: parts,
293 },
293 },
294 },
294 },
295− make([]tools.BaseTool, 0),
295+ nil,
296 )
296 )
297
297
298 var finalResponse *provider.ProviderResponse
298 var finalResponse *provider.ProviderResponse
@@ -745,7 +745,7 @@ func (a *agent) Summarize(ctx context.Context, sessionID string) error {
745 response := a.summarizeProvider.StreamResponse(
745 response := a.summarizeProvider.StreamResponse(
746 summarizeCtx,
746 summarizeCtx,
747 msgsWithPrompt,
747 msgsWithPrompt,
748− make([]tools.BaseTool, 0),
748+ nil,
749 )
749 )
750 var finalResponse *provider.ProviderResponse
750 var finalResponse *provider.ProviderResponse
751 for r := range response {
751 for r := range response {
internal/llm/provider/gemini.go+2−6
@@ -188,9 +188,7 @@ func (g *geminiClient) send(ctx context.Context, messages []message.Message, too
188 Parts: []*genai.Part{{Text: g.providerOptions.systemMessage}},
188 Parts: []*genai.Part{{Text: g.providerOptions.systemMessage}},
189 },
189 },
190 }
190 }
191− if len(tools) > 0 {
192− config.Tools = g.convertTools(tools)
191+ config.Tools = g.convertTools(tools)
193− }
194 chat, _ := g.client.Chats.Create(ctx, model.ID, config, history)
192 chat, _ := g.client.Chats.Create(ctx, model.ID, config, history)
195
193
196 attempts := 0
194 attempts := 0
@@ -290,9 +288,7 @@ func (g *geminiClient) stream(ctx context.Context, messages []message.Message, t
290 Parts: []*genai.Part{{Text: g.providerOptions.systemMessage}},
288 Parts: []*genai.Part{{Text: g.providerOptions.systemMessage}},
291 },
289 },
292 }
290 }
293− if len(tools) > 0 {
294− config.Tools = g.convertTools(tools)
291+ config.Tools = g.convertTools(tools)
295− }
296 chat, _ := g.client.Chats.Create(ctx, model.ID, config, history)
292 chat, _ := g.client.Chats.Create(ctx, model.ID, config, history)
297
293
298 attempts := 0
294 attempts := 0
internal/llm/provider/openai_test.go+1−2
@@ -11,7 +11,6 @@ import (
11
11
12 "github.com/charmbracelet/catwalk/pkg/catwalk"
12 "github.com/charmbracelet/catwalk/pkg/catwalk"
13 "github.com/charmbracelet/crush/internal/config"
13 "github.com/charmbracelet/crush/internal/config"
14− "github.com/charmbracelet/crush/internal/llm/tools"
15 "github.com/charmbracelet/crush/internal/message"
14 "github.com/charmbracelet/crush/internal/message"
16 "github.com/openai/openai-go"
15 "github.com/openai/openai-go"
17 "github.com/openai/openai-go/option"
16 "github.com/openai/openai-go/option"
@@ -79,7 +78,7 @@ func TestOpenAIClientStreamChoices(t *testing.T) {
79 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
78 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
80 defer cancel()
79 defer cancel()
81
80
82− eventsChan := client.stream(ctx, messages, []tools.BaseTool{})
81+ eventsChan := client.stream(ctx, messages, nil)
83
82
84 // Collect events - this will panic without the bounds check
83 // Collect events - this will panic without the bounds check
85 for event := range eventsChan {
84 for event := range eventsChan {