From e40d51cc71c4869e08df501977b7675e8c791860 Mon Sep 17 00:00:00 2001 From: berniegreen Date: Wed, 31 Dec 2025 12:19:27 -0600 Subject: [PATCH 01/15] feat: add domain types for structured streaming (Phase 1) --- internal/domain/stream.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 internal/domain/stream.go diff --git a/internal/domain/stream.go b/internal/domain/stream.go new file mode 100644 index 00000000..91bdcc4f --- /dev/null +++ b/internal/domain/stream.go @@ -0,0 +1,24 @@ +package domain + +// StreamType distinguishes between partial text content and metadata events. +type StreamType string + +const ( + StreamTypeContent StreamType = "content" + StreamTypeUsage StreamType = "usage" + StreamTypeError StreamType = "error" +) + +// StreamUpdate is the unified payload sent through the internal channels. +type StreamUpdate struct { + Type StreamType `json:"type"` + Content string `json:"content,omitempty"` // For text deltas + Usage *UsageMetadata `json:"usage,omitempty"` // For token counts +} + +// UsageMetadata normalizes token counts across different providers. +type UsageMetadata struct { + InputTokens int `json:"input_tokens"` + OutputTokens int `json:"output_tokens"` + TotalTokens int `json:"total_tokens"` +} From 477ca045b0184efe30e85cf3193f3ae3094d2766 Mon Sep 17 00:00:00 2001 From: berniegreen Date: Wed, 31 Dec 2025 12:26:13 -0600 Subject: [PATCH 02/15] refactor: update Vendor interface and Chatter for structured streaming (Phase 2) --- internal/core/chatter.go | 20 ++++++++++++++------ internal/plugins/ai/vendor.go | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/internal/core/chatter.go b/internal/core/chatter.go index adbd581f..37178c75 100644 --- a/internal/core/chatter.go +++ b/internal/core/chatter.go @@ -64,7 +64,7 @@ func (o *Chatter) Send(request *domain.ChatRequest, opts *domain.ChatOptions) (s message := "" if o.Stream { - responseChan := make(chan string) + responseChan := make(chan domain.StreamUpdate) errChan := make(chan error, 1) done := make(chan struct{}) printedStream := false @@ -76,11 +76,19 @@ func (o *Chatter) Send(request *domain.ChatRequest, opts *domain.ChatOptions) (s } }() - for response := range responseChan { - message += response - if !opts.SuppressThink { - fmt.Print(response) - printedStream = true + for update := range responseChan { + switch update.Type { + case domain.StreamTypeContent: + message += update.Content + if !opts.SuppressThink { + fmt.Print(update.Content) + printedStream = true + } + case domain.StreamTypeUsage: + // Placeholder for metadata handling + // Future logic: Store usage in session or context + case domain.StreamTypeError: + errChan <- errors.New(update.Content) } } diff --git a/internal/plugins/ai/vendor.go b/internal/plugins/ai/vendor.go index a9c9b929..c3134618 100644 --- a/internal/plugins/ai/vendor.go +++ b/internal/plugins/ai/vendor.go @@ -12,7 +12,7 @@ import ( type Vendor interface { plugins.Plugin ListModels() ([]string, error) - SendStream([]*chat.ChatCompletionMessage, *domain.ChatOptions, chan string) error + SendStream([]*chat.ChatCompletionMessage, *domain.ChatOptions, chan domain.StreamUpdate) error Send(context.Context, []*chat.ChatCompletionMessage, *domain.ChatOptions) (string, error) NeedsRawMode(modelName string) bool } From 569f50179d341ff2cf8e51e7f8cf58a5376299a3 Mon Sep 17 00:00:00 2001 From: berniegreen Date: Wed, 31 Dec 2025 12:38:38 -0600 Subject: [PATCH 03/15] refactor: implement structured streaming in all AI vendors (Phase 3) --- internal/core/chatter_test.go | 10 +++++-- internal/core/plugin_registry_test.go | 2 +- internal/plugins/ai/anthropic/anthropic.go | 30 +++++++++++++++++-- internal/plugins/ai/bedrock/bedrock.go | 27 +++++++++++++---- internal/plugins/ai/dryrun/dryrun.go | 26 +++++++++++++--- internal/plugins/ai/gemini/gemini.go | 23 ++++++++++++-- internal/plugins/ai/lmstudio/lmstudio.go | 30 +++++++++++++++++-- internal/plugins/ai/ollama/ollama.go | 18 +++++++++-- .../plugins/ai/openai/chat_completions.go | 26 ++++++++++++++-- internal/plugins/ai/openai/openai.go | 14 ++++++--- internal/plugins/ai/perplexity/perplexity.go | 27 ++++++++++++++--- internal/plugins/ai/vendors_test.go | 2 +- internal/plugins/ai/vertexai/vertexai.go | 30 +++++++++++++++++-- 13 files changed, 227 insertions(+), 38 deletions(-) diff --git a/internal/core/chatter_test.go b/internal/core/chatter_test.go index bc4e9aba..4da37377 100644 --- a/internal/core/chatter_test.go +++ b/internal/core/chatter_test.go @@ -14,7 +14,7 @@ import ( // mockVendor implements the ai.Vendor interface for testing type mockVendor struct { sendStreamError error - streamChunks []string + streamChunks []domain.StreamUpdate sendFunc func(context.Context, []*chat.ChatCompletionMessage, *domain.ChatOptions) (string, error) } @@ -45,7 +45,7 @@ func (m *mockVendor) ListModels() ([]string, error) { return []string{"test-model"}, nil } -func (m *mockVendor) SendStream(messages []*chat.ChatCompletionMessage, opts *domain.ChatOptions, responseChan chan string) error { +func (m *mockVendor) SendStream(messages []*chat.ChatCompletionMessage, opts *domain.ChatOptions, responseChan chan domain.StreamUpdate) error { // Send chunks if provided (for successful streaming test) if m.streamChunks != nil { for _, chunk := range m.streamChunks { @@ -169,7 +169,11 @@ func TestChatter_Send_StreamingSuccessfulAggregation(t *testing.T) { db := fsdb.NewDb(tempDir) // Create test chunks that should be aggregated - testChunks := []string{"Hello", " ", "world", "!", " This", " is", " a", " test."} + chunks := []string{"Hello", " ", "world", "!", " This", " is", " a", " test."} + testChunks := make([]domain.StreamUpdate, len(chunks)) + for i, c := range chunks { + testChunks[i] = domain.StreamUpdate{Type: domain.StreamTypeContent, Content: c} + } expectedMessage := "Hello world! This is a test." // Create a mock vendor that will send chunks successfully diff --git a/internal/core/plugin_registry_test.go b/internal/core/plugin_registry_test.go index 23345985..629882dc 100644 --- a/internal/core/plugin_registry_test.go +++ b/internal/core/plugin_registry_test.go @@ -43,7 +43,7 @@ func (m *testVendor) Configure() error { return nil } func (m *testVendor) Setup() error { return nil } func (m *testVendor) SetupFillEnvFileContent(*bytes.Buffer) {} func (m *testVendor) ListModels() ([]string, error) { return m.models, nil } -func (m *testVendor) SendStream([]*chat.ChatCompletionMessage, *domain.ChatOptions, chan string) error { +func (m *testVendor) SendStream([]*chat.ChatCompletionMessage, *domain.ChatOptions, chan domain.StreamUpdate) error { return nil } func (m *testVendor) Send(context.Context, []*chat.ChatCompletionMessage, *domain.ChatOptions) (string, error) { diff --git a/internal/plugins/ai/anthropic/anthropic.go b/internal/plugins/ai/anthropic/anthropic.go index 2176e74e..3c582935 100644 --- a/internal/plugins/ai/anthropic/anthropic.go +++ b/internal/plugins/ai/anthropic/anthropic.go @@ -184,7 +184,7 @@ func parseThinking(level domain.ThinkingLevel) (anthropic.ThinkingConfigParamUni } func (an *Client) SendStream( - msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string, + msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan domain.StreamUpdate, ) (err error) { messages := an.toMessages(msgs) if len(messages) == 0 { @@ -210,9 +210,33 @@ func (an *Client) SendStream( for stream.Next() { event := stream.Current() - // directly send any non-empty delta text + // Handle Content if event.Delta.Text != "" { - channel <- event.Delta.Text + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: event.Delta.Text, + } + } + + // Handle Usage + if event.Message.Usage.InputTokens != 0 || event.Message.Usage.OutputTokens != 0 { + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeUsage, + Usage: &domain.UsageMetadata{ + InputTokens: int(event.Message.Usage.InputTokens), + OutputTokens: int(event.Message.Usage.OutputTokens), + TotalTokens: int(event.Message.Usage.InputTokens + event.Message.Usage.OutputTokens), + }, + } + } else if event.Usage.InputTokens != 0 || event.Usage.OutputTokens != 0 { + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeUsage, + Usage: &domain.UsageMetadata{ + InputTokens: int(event.Usage.InputTokens), + OutputTokens: int(event.Usage.OutputTokens), + TotalTokens: int(event.Usage.InputTokens + event.Usage.OutputTokens), + }, + } } } diff --git a/internal/plugins/ai/bedrock/bedrock.go b/internal/plugins/ai/bedrock/bedrock.go index 15f47c01..5421b2f6 100644 --- a/internal/plugins/ai/bedrock/bedrock.go +++ b/internal/plugins/ai/bedrock/bedrock.go @@ -154,7 +154,7 @@ func (c *BedrockClient) ListModels() ([]string, error) { } // SendStream sends the messages to the Bedrock ConverseStream API -func (c *BedrockClient) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string) (err error) { +func (c *BedrockClient) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan domain.StreamUpdate) (err error) { // Ensure channel is closed on all exit paths to prevent goroutine leaks defer func() { if r := recover(); r != nil { @@ -186,18 +186,35 @@ func (c *BedrockClient) SendStream(msgs []*chat.ChatCompletionMessage, opts *dom case *types.ConverseStreamOutputMemberContentBlockDelta: text, ok := v.Value.Delta.(*types.ContentBlockDeltaMemberText) if ok { - channel <- text.Value + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: text.Value, + } } case *types.ConverseStreamOutputMemberMessageStop: - channel <- "\n" + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: "\n", + } return nil // Let defer handle the close + case *types.ConverseStreamOutputMemberMetadata: + if v.Value.Usage != nil { + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeUsage, + Usage: &domain.UsageMetadata{ + InputTokens: int(*v.Value.Usage.InputTokens), + OutputTokens: int(*v.Value.Usage.OutputTokens), + TotalTokens: int(*v.Value.Usage.TotalTokens), + }, + } + } + // Unused Events case *types.ConverseStreamOutputMemberMessageStart, *types.ConverseStreamOutputMemberContentBlockStart, - *types.ConverseStreamOutputMemberContentBlockStop, - *types.ConverseStreamOutputMemberMetadata: + *types.ConverseStreamOutputMemberContentBlockStop: default: return fmt.Errorf("unknown stream event type: %T", v) diff --git a/internal/plugins/ai/dryrun/dryrun.go b/internal/plugins/ai/dryrun/dryrun.go index 1f36d515..034011c3 100644 --- a/internal/plugins/ai/dryrun/dryrun.go +++ b/internal/plugins/ai/dryrun/dryrun.go @@ -108,12 +108,30 @@ func (c *Client) constructRequest(msgs []*chat.ChatCompletionMessage, opts *doma return builder.String() } -func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string) error { +func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan domain.StreamUpdate) error { defer close(channel) request := c.constructRequest(msgs, opts) - channel <- request - channel <- "\n" - channel <- DryRunResponse + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: request, + } + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: "\n", + } + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: DryRunResponse, + } + // Simulated usage + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeUsage, + Usage: &domain.UsageMetadata{ + InputTokens: 100, + OutputTokens: 50, + TotalTokens: 150, + }, + } return nil } diff --git a/internal/plugins/ai/gemini/gemini.go b/internal/plugins/ai/gemini/gemini.go index fe3035d1..40878f4a 100644 --- a/internal/plugins/ai/gemini/gemini.go +++ b/internal/plugins/ai/gemini/gemini.go @@ -129,7 +129,7 @@ func (o *Client) Send(ctx context.Context, msgs []*chat.ChatCompletionMessage, o return } -func (o *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string) (err error) { +func (o *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan domain.StreamUpdate) (err error) { ctx := context.Background() defer close(channel) @@ -154,13 +154,30 @@ func (o *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha for response, err := range stream { if err != nil { - channel <- fmt.Sprintf("Error: %v\n", err) + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeError, + Content: fmt.Sprintf("Error: %v", err), + } return err } text := o.extractTextFromResponse(response) if text != "" { - channel <- text + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: text, + } + } + + if response.UsageMetadata != nil { + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeUsage, + Usage: &domain.UsageMetadata{ + InputTokens: int(response.UsageMetadata.PromptTokenCount), + OutputTokens: int(response.UsageMetadata.CandidatesTokenCount), + TotalTokens: int(response.UsageMetadata.TotalTokenCount), + }, + } } } diff --git a/internal/plugins/ai/lmstudio/lmstudio.go b/internal/plugins/ai/lmstudio/lmstudio.go index 8e64b88f..f9cae99f 100644 --- a/internal/plugins/ai/lmstudio/lmstudio.go +++ b/internal/plugins/ai/lmstudio/lmstudio.go @@ -87,13 +87,16 @@ func (c *Client) ListModels() ([]string, error) { return models, nil } -func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string) (err error) { +func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan domain.StreamUpdate) (err error) { url := fmt.Sprintf("%s/chat/completions", c.ApiUrl.Value) payload := map[string]any{ "messages": msgs, "model": opts.Model, "stream": true, // Enable streaming + "stream_options": map[string]any{ + "include_usage": true, + }, } var jsonPayload []byte @@ -144,7 +147,7 @@ func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha line = after } - if string(line) == "[DONE]" { + if string(bytes.TrimSpace(line)) == "[DONE]" { break } @@ -153,6 +156,24 @@ func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha continue } + // Handle Usage + if usage, ok := result["usage"].(map[string]any); ok { + var metadata domain.UsageMetadata + if val, ok := usage["prompt_tokens"].(float64); ok { + metadata.InputTokens = int(val) + } + if val, ok := usage["completion_tokens"].(float64); ok { + metadata.OutputTokens = int(val) + } + if val, ok := usage["total_tokens"].(float64); ok { + metadata.TotalTokens = int(val) + } + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeUsage, + Usage: &metadata, + } + } + var choices []any var ok bool if choices, ok = result["choices"].([]any); !ok || len(choices) == 0 { @@ -166,7 +187,10 @@ func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha var content string if content, _ = delta["content"].(string); content != "" { - channel <- content + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: content, + } } } diff --git a/internal/plugins/ai/ollama/ollama.go b/internal/plugins/ai/ollama/ollama.go index 5ab36278..03317dfe 100644 --- a/internal/plugins/ai/ollama/ollama.go +++ b/internal/plugins/ai/ollama/ollama.go @@ -106,7 +106,7 @@ func (o *Client) ListModels() (ret []string, err error) { return } -func (o *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string) (err error) { +func (o *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan domain.StreamUpdate) (err error) { ctx := context.Background() var req ollamaapi.ChatRequest @@ -115,7 +115,21 @@ func (o *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha } respFunc := func(resp ollamaapi.ChatResponse) (streamErr error) { - channel <- resp.Message.Content + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: resp.Message.Content, + } + + if resp.Done { + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeUsage, + Usage: &domain.UsageMetadata{ + InputTokens: resp.PromptEvalCount, + OutputTokens: resp.EvalCount, + TotalTokens: resp.PromptEvalCount + resp.EvalCount, + }, + } + } return } diff --git a/internal/plugins/ai/openai/chat_completions.go b/internal/plugins/ai/openai/chat_completions.go index 9ae444a6..5fc65d9f 100644 --- a/internal/plugins/ai/openai/chat_completions.go +++ b/internal/plugins/ai/openai/chat_completions.go @@ -30,7 +30,7 @@ func (o *Client) sendChatCompletions(ctx context.Context, msgs []*chat.ChatCompl // sendStreamChatCompletions sends a streaming request using the Chat Completions API func (o *Client) sendStreamChatCompletions( - msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string, + msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan domain.StreamUpdate, ) (err error) { defer close(channel) @@ -39,11 +39,28 @@ func (o *Client) sendStreamChatCompletions( for stream.Next() { chunk := stream.Current() if len(chunk.Choices) > 0 && chunk.Choices[0].Delta.Content != "" { - channel <- chunk.Choices[0].Delta.Content + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: chunk.Choices[0].Delta.Content, + } + } + + if chunk.Usage.TotalTokens > 0 { + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeUsage, + Usage: &domain.UsageMetadata{ + InputTokens: int(chunk.Usage.PromptTokens), + OutputTokens: int(chunk.Usage.CompletionTokens), + TotalTokens: int(chunk.Usage.TotalTokens), + }, + } } } if stream.Err() == nil { - channel <- "\n" + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: "\n", + } } return stream.Err() } @@ -65,6 +82,9 @@ func (o *Client) buildChatCompletionParams( ret = openai.ChatCompletionNewParams{ Model: shared.ChatModel(opts.Model), Messages: messages, + StreamOptions: openai.ChatCompletionStreamOptionsParam{ + IncludeUsage: openai.Bool(true), + }, } if !opts.Raw { diff --git a/internal/plugins/ai/openai/openai.go b/internal/plugins/ai/openai/openai.go index db48f856..e364c66c 100644 --- a/internal/plugins/ai/openai/openai.go +++ b/internal/plugins/ai/openai/openai.go @@ -108,7 +108,7 @@ func (o *Client) ListModels() (ret []string, err error) { } func (o *Client) SendStream( - msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string, + msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan domain.StreamUpdate, ) (err error) { // Use Responses API for OpenAI, Chat Completions API for other providers if o.supportsResponsesAPI() { @@ -118,7 +118,7 @@ func (o *Client) SendStream( } func (o *Client) sendStreamResponses( - msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string, + msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan domain.StreamUpdate, ) (err error) { defer close(channel) @@ -128,7 +128,10 @@ func (o *Client) sendStreamResponses( event := stream.Current() switch event.Type { case string(constant.ResponseOutputTextDelta("").Default()): - channel <- event.AsResponseOutputTextDelta().Delta + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: event.AsResponseOutputTextDelta().Delta, + } case string(constant.ResponseOutputTextDone("").Default()): // The Responses API sends the full text again in the // final "done" event. Since we've already streamed all @@ -138,7 +141,10 @@ func (o *Client) sendStreamResponses( } } if stream.Err() == nil { - channel <- "\n" + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: "\n", + } } return stream.Err() } diff --git a/internal/plugins/ai/perplexity/perplexity.go b/internal/plugins/ai/perplexity/perplexity.go index 3f0a6198..4ec5f2b1 100644 --- a/internal/plugins/ai/perplexity/perplexity.go +++ b/internal/plugins/ai/perplexity/perplexity.go @@ -123,7 +123,7 @@ func (c *Client) Send(ctx context.Context, msgs []*chat.ChatCompletionMessage, o return content.String(), nil } -func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string) error { +func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan domain.StreamUpdate) error { if c.client == nil { if err := c.Configure(); err != nil { close(channel) // Ensure channel is closed on error @@ -196,7 +196,21 @@ func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha content = resp.Choices[0].Message.Content } if content != "" { - channel <- content + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: content, + } + } + } + + if resp.Usage.TotalTokens != 0 { + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeUsage, + Usage: &domain.UsageMetadata{ + InputTokens: int(resp.Usage.PromptTokens), + OutputTokens: int(resp.Usage.CompletionTokens), + TotalTokens: int(resp.Usage.TotalTokens), + }, } } } @@ -205,9 +219,14 @@ func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha if lastResponse != nil { citations := lastResponse.GetCitations() if len(citations) > 0 { - channel <- "\n\n# CITATIONS\n\n" + var citationsText strings.Builder + citationsText.WriteString("\n\n# CITATIONS\n\n") for i, citation := range citations { - channel <- fmt.Sprintf("- [%d] %s\n", i+1, citation) + citationsText.WriteString(fmt.Sprintf("- [%d] %s\n", i+1, citation)) + } + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: citationsText.String(), } } } diff --git a/internal/plugins/ai/vendors_test.go b/internal/plugins/ai/vendors_test.go index 42cf40fb..4534712d 100644 --- a/internal/plugins/ai/vendors_test.go +++ b/internal/plugins/ai/vendors_test.go @@ -20,7 +20,7 @@ func (v *stubVendor) Configure() error { return nil } func (v *stubVendor) Setup() error { return nil } func (v *stubVendor) SetupFillEnvFileContent(*bytes.Buffer) {} func (v *stubVendor) ListModels() ([]string, error) { return nil, nil } -func (v *stubVendor) SendStream([]*chat.ChatCompletionMessage, *domain.ChatOptions, chan string) error { +func (v *stubVendor) SendStream([]*chat.ChatCompletionMessage, *domain.ChatOptions, chan domain.StreamUpdate) error { return nil } func (v *stubVendor) Send(context.Context, []*chat.ChatCompletionMessage, *domain.ChatOptions) (string, error) { diff --git a/internal/plugins/ai/vertexai/vertexai.go b/internal/plugins/ai/vertexai/vertexai.go index 0860be0f..23ed4ac2 100644 --- a/internal/plugins/ai/vertexai/vertexai.go +++ b/internal/plugins/ai/vertexai/vertexai.go @@ -107,7 +107,7 @@ func (c *Client) Send(ctx context.Context, msgs []*chat.ChatCompletionMessage, o return strings.Join(textParts, ""), nil } -func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string) error { +func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan domain.StreamUpdate) error { if c.client == nil { close(channel) return fmt.Errorf("VertexAI client not initialized") @@ -133,8 +133,34 @@ func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha // Process stream for stream.Next() { event := stream.Current() + + // Handle Content if event.Delta.Text != "" { - channel <- event.Delta.Text + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeContent, + Content: event.Delta.Text, + } + } + + // Handle Usage + if event.Message.Usage.InputTokens != 0 || event.Message.Usage.OutputTokens != 0 { + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeUsage, + Usage: &domain.UsageMetadata{ + InputTokens: int(event.Message.Usage.InputTokens), + OutputTokens: int(event.Message.Usage.OutputTokens), + TotalTokens: int(event.Message.Usage.InputTokens + event.Message.Usage.OutputTokens), + }, + } + } else if event.Usage.InputTokens != 0 || event.Usage.OutputTokens != 0 { + channel <- domain.StreamUpdate{ + Type: domain.StreamTypeUsage, + Usage: &domain.UsageMetadata{ + InputTokens: int(event.Usage.InputTokens), + OutputTokens: int(event.Usage.OutputTokens), + TotalTokens: int(event.Usage.InputTokens + event.Usage.OutputTokens), + }, + } } } From 66d3bf786ed2ffd9a55cd113dce1f70d659526b8 Mon Sep 17 00:00:00 2001 From: berniegreen Date: Wed, 31 Dec 2025 12:41:06 -0600 Subject: [PATCH 04/15] feat: implement CLI support for metadata display (Phase 4) --- internal/cli/flags.go | 2 ++ internal/core/chatter.go | 7 +++++-- internal/domain/domain.go | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/cli/flags.go b/internal/cli/flags.go index e018bc47..274c856c 100644 --- a/internal/cli/flags.go +++ b/internal/cli/flags.go @@ -104,6 +104,7 @@ type Flags struct { Notification bool `long:"notification" yaml:"notification" description:"Send desktop notification when command completes"` NotificationCommand string `long:"notification-command" yaml:"notificationCommand" description:"Custom command to run for notifications (overrides built-in notifications)"` Thinking domain.ThinkingLevel `long:"thinking" yaml:"thinking" description:"Set reasoning/thinking level (e.g., off, low, medium, high, or numeric tokens for Anthropic or Google Gemini)"` + ShowMetadata bool `long:"show-metadata" description:"Print metadata to stderr"` Debug int `long:"debug" description:"Set debug level (0=off, 1=basic, 2=detailed, 3=trace)" default:"0"` } @@ -459,6 +460,7 @@ func (o *Flags) BuildChatOptions() (ret *domain.ChatOptions, err error) { Voice: o.Voice, Notification: o.Notification || o.NotificationCommand != "", NotificationCommand: o.NotificationCommand, + ShowMetadata: o.ShowMetadata, } return } diff --git a/internal/core/chatter.go b/internal/core/chatter.go index 37178c75..61aea454 100644 --- a/internal/core/chatter.go +++ b/internal/core/chatter.go @@ -85,9 +85,12 @@ func (o *Chatter) Send(request *domain.ChatRequest, opts *domain.ChatOptions) (s printedStream = true } case domain.StreamTypeUsage: - // Placeholder for metadata handling - // Future logic: Store usage in session or context + if opts.ShowMetadata && update.Usage != nil { + fmt.Fprintf(os.Stderr, "\n[Metadata] Input: %d | Output: %d | Total: %d\n", + update.Usage.InputTokens, update.Usage.OutputTokens, update.Usage.TotalTokens) + } case domain.StreamTypeError: + fmt.Fprintf(os.Stderr, "Error: %s\n", update.Content) errChan <- errors.New(update.Content) } } diff --git a/internal/domain/domain.go b/internal/domain/domain.go index bd6fbbdf..3c1b8ed0 100644 --- a/internal/domain/domain.go +++ b/internal/domain/domain.go @@ -51,6 +51,7 @@ type ChatOptions struct { Voice string Notification bool NotificationCommand string + ShowMetadata bool } // NormalizeMessages remove empty messages and ensure messages order user-assist-user From c539b1edfc4a6e338c6224edba20ee897f6c604a Mon Sep 17 00:00:00 2001 From: berniegreen Date: Wed, 31 Dec 2025 12:43:48 -0600 Subject: [PATCH 05/15] feat: implement REST API support for metadata streaming (Phase 5) --- internal/core/chatter.go | 13 ++++++--- internal/domain/domain.go | 2 ++ internal/server/chat.go | 58 ++++++++++++++++++--------------------- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/internal/core/chatter.go b/internal/core/chatter.go index 61aea454..101ed364 100644 --- a/internal/core/chatter.go +++ b/internal/core/chatter.go @@ -77,25 +77,30 @@ func (o *Chatter) Send(request *domain.ChatRequest, opts *domain.ChatOptions) (s }() for update := range responseChan { + if opts.UpdateChan != nil { + opts.UpdateChan <- update + } switch update.Type { case domain.StreamTypeContent: message += update.Content - if !opts.SuppressThink { + if !opts.SuppressThink && !opts.Quiet { fmt.Print(update.Content) printedStream = true } case domain.StreamTypeUsage: - if opts.ShowMetadata && update.Usage != nil { + if opts.ShowMetadata && update.Usage != nil && !opts.Quiet { fmt.Fprintf(os.Stderr, "\n[Metadata] Input: %d | Output: %d | Total: %d\n", update.Usage.InputTokens, update.Usage.OutputTokens, update.Usage.TotalTokens) } case domain.StreamTypeError: - fmt.Fprintf(os.Stderr, "Error: %s\n", update.Content) + if !opts.Quiet { + fmt.Fprintf(os.Stderr, "Error: %s\n", update.Content) + } errChan <- errors.New(update.Content) } } - if printedStream && !opts.SuppressThink && !strings.HasSuffix(message, "\n") { + if printedStream && !opts.SuppressThink && !strings.HasSuffix(message, "\n") && !opts.Quiet { fmt.Println() } diff --git a/internal/domain/domain.go b/internal/domain/domain.go index 3c1b8ed0..2179e28b 100644 --- a/internal/domain/domain.go +++ b/internal/domain/domain.go @@ -52,6 +52,8 @@ type ChatOptions struct { Notification bool NotificationCommand string ShowMetadata bool + Quiet bool + UpdateChan chan StreamUpdate } // NormalizeMessages remove empty messages and ensure messages order user-assist-user diff --git a/internal/server/chat.go b/internal/server/chat.go index fe53ee9e..9854d824 100755 --- a/internal/server/chat.go +++ b/internal/server/chat.go @@ -40,9 +40,10 @@ type ChatRequest struct { } type StreamResponse struct { - Type string `json:"type"` // "content", "error", "complete" - Format string `json:"format"` // "markdown", "mermaid", "plain" - Content string `json:"content"` // The actual content + Type string `json:"type"` // "content", "usage", "error", "complete" + Format string `json:"format,omitempty"` // "markdown", "mermaid", "plain" + Content string `json:"content,omitempty"` + Usage *domain.UsageMetadata `json:"usage,omitempty"` } func NewChatHandler(r *gin.Engine, registry *core.PluginRegistry, db *fsdb.Db) *ChatHandler { @@ -98,7 +99,7 @@ func (h *ChatHandler) HandleChat(c *gin.Context) { log.Printf("Processing prompt %d: Model=%s Pattern=%s Context=%s", i+1, prompt.Model, prompt.PatternName, prompt.ContextName) - streamChan := make(chan string) + streamChan := make(chan domain.StreamUpdate) go func(p PromptRequest) { defer close(streamChan) @@ -117,10 +118,10 @@ func (h *ChatHandler) HandleChat(c *gin.Context) { } } - chatter, err := h.registry.GetChatter(p.Model, 2048, p.Vendor, "", false, false) + chatter, err := h.registry.GetChatter(p.Model, 2048, p.Vendor, "", true, false) if err != nil { log.Printf("Error creating chatter: %v", err) - streamChan <- fmt.Sprintf("Error: %v", err) + streamChan <- domain.StreamUpdate{Type: domain.StreamTypeError, Content: fmt.Sprintf("Error: %v", err)} return } @@ -144,49 +145,44 @@ func (h *ChatHandler) HandleChat(c *gin.Context) { FrequencyPenalty: request.FrequencyPenalty, PresencePenalty: request.PresencePenalty, Thinking: request.Thinking, + UpdateChan: streamChan, + Quiet: true, } - session, err := chatter.Send(chatReq, opts) + _, err = chatter.Send(chatReq, opts) if err != nil { log.Printf("Error from chatter.Send: %v", err) - streamChan <- fmt.Sprintf("Error: %v", err) + // Error already sent to streamChan via domain.StreamTypeError if occurred in Send loop return } - - if session == nil { - log.Printf("No session returned from chatter.Send") - streamChan <- "Error: No response from model" - return - } - - lastMsg := session.GetLastMessage() - if lastMsg != nil { - streamChan <- lastMsg.Content - } else { - log.Printf("No message content in session") - streamChan <- "Error: No response content" - } }(prompt) - for content := range streamChan { + for update := range streamChan { select { case <-clientGone: return default: var response StreamResponse - if strings.HasPrefix(content, "Error:") { + switch update.Type { + case domain.StreamTypeContent: + response = StreamResponse{ + Type: "content", + Format: detectFormat(update.Content), + Content: update.Content, + } + case domain.StreamTypeUsage: + response = StreamResponse{ + Type: "usage", + Usage: update.Usage, + } + case domain.StreamTypeError: response = StreamResponse{ Type: "error", Format: "plain", - Content: content, - } - } else { - response = StreamResponse{ - Type: "content", - Format: detectFormat(content), - Content: content, + Content: update.Content, } } + if err := writeSSEResponse(c.Writer, response); err != nil { log.Printf("Error writing response: %v", err) return From 8166ee7a18e13350e738be7e31b3160241b17e51 Mon Sep 17 00:00:00 2001 From: berniegreen Date: Wed, 31 Dec 2025 15:13:20 -0600 Subject: [PATCH 06/15] docs: update swagger documentation and fix dryrun tests --- docs/docs.go | 33 +++++++++++++++++++++-- docs/swagger.json | 33 +++++++++++++++++++++-- docs/swagger.yaml | 23 ++++++++++++++-- internal/plugins/ai/dryrun/dryrun_test.go | 4 +-- 4 files changed, 85 insertions(+), 8 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 62c61101..e67df397 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -289,6 +289,20 @@ const docTemplate = `{ "ThinkingHigh" ] }, + "domain.UsageMetadata": { + "type": "object", + "properties": { + "input_tokens": { + "type": "integer" + }, + "output_tokens": { + "type": "integer" + }, + "total_tokens": { + "type": "integer" + } + } + }, "fsdb.Pattern": { "type": "object", "properties": { @@ -360,6 +374,9 @@ const docTemplate = `{ "$ref": "#/definitions/restapi.PromptRequest" } }, + "quiet": { + "type": "boolean" + }, "raw": { "type": "boolean" }, @@ -372,6 +389,9 @@ const docTemplate = `{ "seed": { "type": "integer" }, + "showMetadata": { + "type": "boolean" + }, "suppressThink": { "type": "boolean" }, @@ -392,6 +412,9 @@ const docTemplate = `{ "type": "number", "format": "float64" }, + "updateChan": { + "type": "object" + }, "voice": { "type": "string" } @@ -423,6 +446,10 @@ const docTemplate = `{ "patternName": { "type": "string" }, + "sessionName": { + "description": "Session name for multi-turn conversations", + "type": "string" + }, "strategyName": { "description": "Optional strategy name", "type": "string" @@ -446,7 +473,6 @@ const docTemplate = `{ "type": "object", "properties": { "content": { - "description": "The actual content", "type": "string" }, "format": { @@ -454,8 +480,11 @@ const docTemplate = `{ "type": "string" }, "type": { - "description": "\"content\", \"error\", \"complete\"", + "description": "\"content\", \"usage\", \"error\", \"complete\"", "type": "string" + }, + "usage": { + "$ref": "#/definitions/domain.UsageMetadata" } } }, diff --git a/docs/swagger.json b/docs/swagger.json index 547443dd..749c6e06 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -283,6 +283,20 @@ "ThinkingHigh" ] }, + "domain.UsageMetadata": { + "type": "object", + "properties": { + "input_tokens": { + "type": "integer" + }, + "output_tokens": { + "type": "integer" + }, + "total_tokens": { + "type": "integer" + } + } + }, "fsdb.Pattern": { "type": "object", "properties": { @@ -354,6 +368,9 @@ "$ref": "#/definitions/restapi.PromptRequest" } }, + "quiet": { + "type": "boolean" + }, "raw": { "type": "boolean" }, @@ -366,6 +383,9 @@ "seed": { "type": "integer" }, + "showMetadata": { + "type": "boolean" + }, "suppressThink": { "type": "boolean" }, @@ -386,6 +406,9 @@ "type": "number", "format": "float64" }, + "updateChan": { + "type": "object" + }, "voice": { "type": "string" } @@ -417,6 +440,10 @@ "patternName": { "type": "string" }, + "sessionName": { + "description": "Session name for multi-turn conversations", + "type": "string" + }, "strategyName": { "description": "Optional strategy name", "type": "string" @@ -440,7 +467,6 @@ "type": "object", "properties": { "content": { - "description": "The actual content", "type": "string" }, "format": { @@ -448,8 +474,11 @@ "type": "string" }, "type": { - "description": "\"content\", \"error\", \"complete\"", + "description": "\"content\", \"usage\", \"error\", \"complete\"", "type": "string" + }, + "usage": { + "$ref": "#/definitions/domain.UsageMetadata" } } }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index f1629f92..53184584 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -12,6 +12,15 @@ definitions: - ThinkingLow - ThinkingMedium - ThinkingHigh + domain.UsageMetadata: + properties: + input_tokens: + type: integer + output_tokens: + type: integer + total_tokens: + type: integer + type: object fsdb.Pattern: properties: description: @@ -60,6 +69,8 @@ definitions: items: $ref: '#/definitions/restapi.PromptRequest' type: array + quiet: + type: boolean raw: type: boolean search: @@ -68,6 +79,8 @@ definitions: type: string seed: type: integer + showMetadata: + type: boolean suppressThink: type: boolean temperature: @@ -82,6 +95,8 @@ definitions: topP: format: float64 type: number + updateChan: + type: object voice: type: string type: object @@ -102,6 +117,9 @@ definitions: type: string patternName: type: string + sessionName: + description: Session name for multi-turn conversations + type: string strategyName: description: Optional strategy name type: string @@ -118,14 +136,15 @@ definitions: restapi.StreamResponse: properties: content: - description: The actual content type: string format: description: '"markdown", "mermaid", "plain"' type: string type: - description: '"content", "error", "complete"' + description: '"content", "usage", "error", "complete"' type: string + usage: + $ref: '#/definitions/domain.UsageMetadata' type: object restapi.YouTubeRequest: properties: diff --git a/internal/plugins/ai/dryrun/dryrun_test.go b/internal/plugins/ai/dryrun/dryrun_test.go index 0f8825ac..a5db58c3 100644 --- a/internal/plugins/ai/dryrun/dryrun_test.go +++ b/internal/plugins/ai/dryrun/dryrun_test.go @@ -39,7 +39,7 @@ func TestSendStream_SendsMessages(t *testing.T) { opts := &domain.ChatOptions{ Model: "dry-run-model", } - channel := make(chan string) + channel := make(chan domain.StreamUpdate) go func() { err := client.SendStream(msgs, opts, channel) if err != nil { @@ -48,7 +48,7 @@ func TestSendStream_SendsMessages(t *testing.T) { }() var receivedMessages []string for msg := range channel { - receivedMessages = append(receivedMessages, msg) + receivedMessages = append(receivedMessages, msg.Content) } if len(receivedMessages) == 0 { t.Errorf("Expected to receive messages, but got none") From 07457d86d37561aa0c7aac7250706d40d948a879 Mon Sep 17 00:00:00 2001 From: berniegreen Date: Wed, 31 Dec 2025 15:15:15 -0600 Subject: [PATCH 07/15] docs: document --show-metadata flag in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3107d2c4..da6b72ed 100644 --- a/README.md +++ b/README.md @@ -705,6 +705,7 @@ Application Options: --yt-dlp-args= Additional arguments to pass to yt-dlp (e.g. '--cookies-from-browser brave') --thinking= Set reasoning/thinking level (e.g., off, low, medium, high, or numeric tokens for Anthropic or Google Gemini) + --show-metadata Print metadata (input/output tokens) to stderr --debug= Set debug level (0: off, 1: basic, 2: detailed, 3: trace) Help Options: -h, --help Show this help message From c7ecac3262ecf2ddc847c06e9926c703d7bd86fc Mon Sep 17 00:00:00 2001 From: berniegreen Date: Wed, 31 Dec 2025 15:56:20 -0600 Subject: [PATCH 08/15] test: add test for metadata stream propagation --- internal/core/chatter_test.go | 80 +++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/internal/core/chatter_test.go b/internal/core/chatter_test.go index 4da37377..c748aa3c 100644 --- a/internal/core/chatter_test.go +++ b/internal/core/chatter_test.go @@ -232,3 +232,83 @@ func TestChatter_Send_StreamingSuccessfulAggregation(t *testing.T) { t.Errorf("Expected aggregated message %q, got %q", expectedMessage, assistantMessage.Content) } } + +func TestChatter_Send_StreamingMetadataPropagation(t *testing.T) { + // Create a temporary database for testing + tempDir := t.TempDir() + db := fsdb.NewDb(tempDir) + + // Create test chunks: one content, one usage metadata + testChunks := []domain.StreamUpdate{ + { + Type: domain.StreamTypeContent, + Content: "Test content", + }, + { + Type: domain.StreamTypeUsage, + Usage: &domain.UsageMetadata{ + InputTokens: 10, + OutputTokens: 5, + TotalTokens: 15, + }, + }, + } + + // Create a mock vendor + mockVendor := &mockVendor{ + sendStreamError: nil, + streamChunks: testChunks, + } + + // Create chatter with streaming enabled + chatter := &Chatter{ + db: db, + Stream: true, + vendor: mockVendor, + model: "test-model", + } + + // Create a test request + request := &domain.ChatRequest{ + Message: &chat.ChatCompletionMessage{ + Role: chat.ChatMessageRoleUser, + Content: "test message", + }, + } + + // Create an update channel to capture stream events + updateChan := make(chan domain.StreamUpdate, 10) + + // Create test options with UpdateChan + opts := &domain.ChatOptions{ + Model: "test-model", + UpdateChan: updateChan, + Quiet: true, // Suppress stdout/stderr + } + + // Call Send + _, err := chatter.Send(request, opts) + if err != nil { + t.Fatalf("Expected no error, but got: %v", err) + } + close(updateChan) + + // Verify we received the metadata event + var usageReceived bool + for update := range updateChan { + if update.Type == domain.StreamTypeUsage { + usageReceived = true + if update.Usage == nil { + t.Error("Expected usage metadata to be non-nil") + } else { + if update.Usage.TotalTokens != 15 { + t.Errorf("Expected 15 total tokens, got %d", update.Usage.TotalTokens) + } + } + } + } + + if !usageReceived { + t.Error("Expected to receive a usage metadata update, but didn't") + } +} \ No newline at end of file From b04346008bb520f1f33c31483450bc8e322af513 Mon Sep 17 00:00:00 2001 From: berniegreen Date: Wed, 31 Dec 2025 16:59:30 -0600 Subject: [PATCH 09/15] fix: add missing newline to end of chatter_test.go --- internal/core/chatter_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/core/chatter_test.go b/internal/core/chatter_test.go index c748aa3c..6dcc1ce0 100644 --- a/internal/core/chatter_test.go +++ b/internal/core/chatter_test.go @@ -311,4 +311,4 @@ func TestChatter_Send_StreamingMetadataPropagation(t *testing.T) { if !usageReceived { t.Error("Expected to receive a usage metadata update, but didn't") } -} \ No newline at end of file +} From 11e9e16078d3d3b9bfbbe15f47923a7f16736759 Mon Sep 17 00:00:00 2001 From: Kayvan Sylvan Date: Sat, 3 Jan 2026 14:07:50 -0800 Subject: [PATCH 10/15] fix: improve git worktree status detection to ignore staged-only files - Add worktree-specific check for actual working directory changes - Filter out files that are only staged but not in worktree - Check worktree status codes instead of using IsClean method - Update GetStatusDetails to only include worktree-modified files - Ignore unmodified and untracked files in clean check --- cmd/generate_changelog/internal/git/walker.go | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/cmd/generate_changelog/internal/git/walker.go b/cmd/generate_changelog/internal/git/walker.go index 93e9347d..b98c96f8 100644 --- a/cmd/generate_changelog/internal/git/walker.go +++ b/cmd/generate_changelog/internal/git/walker.go @@ -433,7 +433,17 @@ func (w *Walker) IsWorkingDirectoryClean() (bool, error) { return false, fmt.Errorf("failed to get git status: %w", err) } - return status.IsClean(), nil + // In worktrees, we need to check if files are actually modified in the working directory + // Ignore files that are only staged (Added) but not present in the worktree filesystem + for _, fileStatus := range status { + // Check if there are any changes in the working directory (not just staging) + // Worktree status codes: ' ' = unmodified, 'M' = modified, 'D' = deleted, '?' = untracked + if fileStatus.Worktree != git.Unmodified && fileStatus.Worktree != git.Untracked { + return false, nil + } + } + + return true, nil } // GetStatusDetails returns a detailed status of the working directory @@ -448,13 +458,12 @@ func (w *Walker) GetStatusDetails() (string, error) { return "", fmt.Errorf("failed to get git status: %w", err) } - if status.IsClean() { - return "", nil - } - var details strings.Builder for file, fileStatus := range status { - details.WriteString(fmt.Sprintf(" %c%c %s\n", fileStatus.Staging, fileStatus.Worktree, file)) + // Only include files with actual working directory changes + if fileStatus.Worktree != git.Unmodified && fileStatus.Worktree != git.Untracked { + details.WriteString(fmt.Sprintf(" %c%c %s\n", fileStatus.Staging, fileStatus.Worktree, file)) + } } return details.String(), nil From 53bad5b70d77c5c2df1ff974bbd8f3a809378fd8 Mon Sep 17 00:00:00 2001 From: Kayvan Sylvan Date: Sat, 3 Jan 2026 14:16:09 -0800 Subject: [PATCH 11/15] fix: IsWorkingDirectoryClean to work correctly in worktrees - Check filesystem existence of staged files to handle worktree scenarios - Ignore files staged in main repo that don't exist in worktree - Allow staged files that exist in worktree to be committed normally Co-Authored-By: Warp --- cmd/generate_changelog/internal/git/walker.go | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/cmd/generate_changelog/internal/git/walker.go b/cmd/generate_changelog/internal/git/walker.go index b98c96f8..b5ce43f9 100644 --- a/cmd/generate_changelog/internal/git/walker.go +++ b/cmd/generate_changelog/internal/git/walker.go @@ -2,6 +2,8 @@ package git import ( "fmt" + "os" + "path/filepath" "regexp" "strconv" "strings" @@ -433,14 +435,27 @@ func (w *Walker) IsWorkingDirectoryClean() (bool, error) { return false, fmt.Errorf("failed to get git status: %w", err) } - // In worktrees, we need to check if files are actually modified in the working directory - // Ignore files that are only staged (Added) but not present in the worktree filesystem - for _, fileStatus := range status { - // Check if there are any changes in the working directory (not just staging) - // Worktree status codes: ' ' = unmodified, 'M' = modified, 'D' = deleted, '?' = untracked + worktreePath := worktree.Filesystem.Root() + + // In worktrees, files staged in the main repo may appear in status but not exist in the worktree + // We need to check both the working directory status AND filesystem existence + for file, fileStatus := range status { + // Check if there are any changes in the working directory if fileStatus.Worktree != git.Unmodified && fileStatus.Worktree != git.Untracked { return false, nil } + + // For staged files (Added, Modified in index), verify they exist in this worktree's filesystem + // This handles the worktree case where the main repo has staged files that don't exist here + if fileStatus.Staging != git.Unmodified && fileStatus.Staging != git.Untracked { + filePath := filepath.Join(worktreePath, file) + if _, err := os.Stat(filePath); os.IsNotExist(err) { + // File is staged but doesn't exist in this worktree - ignore it + continue + } + // File is staged AND exists in this worktree - not clean + return false, nil + } } return true, nil From 672b920a891b17e640d99276d5b1da55c93e6717 Mon Sep 17 00:00:00 2001 From: Kayvan Sylvan Date: Sat, 3 Jan 2026 14:29:04 -0800 Subject: [PATCH 12/15] chore: incoming 1912 changelog entry --- cmd/generate_changelog/incoming/1912.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 cmd/generate_changelog/incoming/1912.txt diff --git a/cmd/generate_changelog/incoming/1912.txt b/cmd/generate_changelog/incoming/1912.txt new file mode 100644 index 00000000..c2dbb159 --- /dev/null +++ b/cmd/generate_changelog/incoming/1912.txt @@ -0,0 +1,7 @@ +### PR [#1912](https://github.com/danielmiessler/Fabric/pull/1912) by [berniegreen](https://github.com/berniegreen): refactor: implement structured streaming and metadata support + +- Feat: add domain types for structured streaming (Phase 1) +- Refactor: update Vendor interface and Chatter for structured streaming (Phase 2) +- Refactor: implement structured streaming in all AI vendors (Phase 3) +- Feat: implement CLI support for metadata display (Phase 4) +- Feat: implement REST API support for metadata streaming (Phase 5) From d2ebe99e0ed11bc3865f0f425d19a11da3dbf372 Mon Sep 17 00:00:00 2001 From: Kayvan Sylvan Date: Sat, 3 Jan 2026 14:29:18 -0800 Subject: [PATCH 13/15] fix: use native git CLI for add/commit in worktrees go-git has issues with worktrees where the object database isn't properly shared, causing 'invalid object' errors when trying to commit. Switching to native git CLI for add and commit operations resolves this. This fixes generate_changelog failing in worktrees with errors like: - 'cannot create empty commit: clean working tree' - 'error: invalid object ... Error building trees' Co-Authored-By: Warp --- cmd/generate_changelog/internal/git/walker.go | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/cmd/generate_changelog/internal/git/walker.go b/cmd/generate_changelog/internal/git/walker.go index b5ce43f9..a8c03c8d 100644 --- a/cmd/generate_changelog/internal/git/walker.go +++ b/cmd/generate_changelog/internal/git/walker.go @@ -3,6 +3,7 @@ package git import ( "fmt" "os" + "os/exec" "path/filepath" "regexp" "strconv" @@ -485,57 +486,53 @@ func (w *Walker) GetStatusDetails() (string, error) { } // AddFile adds a file to the git index +// Uses native git CLI instead of go-git to properly handle worktree scenarios func (w *Walker) AddFile(filename string) error { worktree, err := w.repo.Worktree() if err != nil { return fmt.Errorf("failed to get worktree: %w", err) } - _, err = worktree.Add(filename) + worktreePath := worktree.Filesystem.Root() + + // Use native git add command to avoid go-git worktree issues + cmd := exec.Command("git", "add", filename) + cmd.Dir = worktreePath + + output, err := cmd.CombinedOutput() if err != nil { - return fmt.Errorf("failed to add file %s: %w", filename, err) + return fmt.Errorf("failed to add file %s: %w (output: %s)", filename, err, string(output)) } return nil } // CommitChanges creates a commit with the given message +// Uses native git CLI instead of go-git to properly handle worktree scenarios func (w *Walker) CommitChanges(message string) (plumbing.Hash, error) { worktree, err := w.repo.Worktree() if err != nil { return plumbing.ZeroHash, fmt.Errorf("failed to get worktree: %w", err) } - // Get git config for author information - cfg, err := w.repo.Config() + worktreePath := worktree.Filesystem.Root() + + // Use native git commit command to avoid go-git worktree issues + cmd := exec.Command("git", "commit", "-m", message) + cmd.Dir = worktreePath + + output, err := cmd.CombinedOutput() if err != nil { - return plumbing.ZeroHash, fmt.Errorf("failed to get git config: %w", err) + return plumbing.ZeroHash, fmt.Errorf("failed to commit: %w (output: %s)", err, string(output)) } - var authorName, authorEmail string - if cfg.User.Name != "" { - authorName = cfg.User.Name - } else { - authorName = "Changelog Bot" - } - if cfg.User.Email != "" { - authorEmail = cfg.User.Email - } else { - authorEmail = "bot@changelog.local" - } - - commit, err := worktree.Commit(message, &git.CommitOptions{ - Author: &object.Signature{ - Name: authorName, - Email: authorEmail, - When: time.Now(), - }, - }) + // Get the commit hash from HEAD + ref, err := w.repo.Head() if err != nil { - return plumbing.ZeroHash, fmt.Errorf("failed to commit: %w", err) + return plumbing.ZeroHash, fmt.Errorf("failed to get HEAD after commit: %w", err) } - return commit, nil + return ref.Hash(), nil } // PushToRemote pushes the current branch to the remote repository From 1aea48d0037ede137584be6ec6674ac2899f9664 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 3 Jan 2026 22:36:16 +0000 Subject: [PATCH 14/15] chore(release): Update version to v1.4.366 --- CHANGELOG.md | 35 +++++++++++++++++++++++ cmd/fabric/version.go | 2 +- cmd/generate_changelog/changelog.db | Bin 3502080 -> 3514368 bytes cmd/generate_changelog/incoming/1909.txt | 4 --- nix/pkgs/fabric/version.nix | 2 +- 5 files changed, 37 insertions(+), 6 deletions(-) delete mode 100644 cmd/generate_changelog/incoming/1909.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index cd939db3..5d5b2ae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,40 @@ # Changelog +## v1.4.366 (2025-12-31) + +### PR [#1909](https://github.com/danielmiessler/Fabric/pull/1909) by [copyleftdev](https://github.com/copyleftdev): feat: add greybeard_secure_prompt_engineer pattern + +- Added greybeard_secure_prompt_engineer pattern +- Updated changelog with incoming entry + +### Direct commits + +- Fix: use native git CLI for add/commit in worktrees +go-git has issues with worktrees where the object database isn't properly +shared, causing 'invalid object' errors when trying to commit. Switching +to native git CLI for add and commit operations resolves this. +This fixes generate_changelog failing in worktrees with errors like: +- 'cannot create empty commit: clean working tree' + +- 'error: invalid object ... Error building trees' +Co-Authored-By: Warp +- Fix: IsWorkingDirectoryClean to work correctly in worktrees + +- Check filesystem existence of staged files to handle worktree scenarios +- Ignore files staged in main repo that don't exist in worktree + +- Allow staged files that exist in worktree to be committed normally +Co-Authored-By: Warp +- Fix: improve git worktree status detection to ignore staged-only files + +- Add worktree-specific check for actual working directory changes +- Filter out files that are only staged but not in worktree + +- Check worktree status codes instead of using IsClean method +- Update GetStatusDetails to only include worktree-modified files + +- Ignore unmodified and untracked files in clean check + ## v1.4.365 (2025-12-30) ### PR [#1908](https://github.com/danielmiessler/Fabric/pull/1908) by [rodaddy](https://github.com/rodaddy): feat(ai): add VertexAI provider for Claude models diff --git a/cmd/fabric/version.go b/cmd/fabric/version.go index 13c8b766..5eb636d0 100644 --- a/cmd/fabric/version.go +++ b/cmd/fabric/version.go @@ -1,3 +1,3 @@ package main -var version = "v1.4.365" +var version = "v1.4.366" diff --git a/cmd/generate_changelog/changelog.db b/cmd/generate_changelog/changelog.db index b239bc71351764fb4661f98e2a18c05a20a8f8ae..2491cd3b774ae7420714f780f4112f293f39e782 100644 GIT binary patch delta 76688 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⁣0MUhyf3}ejS#` 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 delta 50874 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 Date: Sat, 3 Jan 2026 22:53:06 +0000 Subject: [PATCH 15/15] chore(release): Update version to v1.4.367 --- CHANGELOG.md | 10 ++++++++++ cmd/fabric/version.go | 2 +- cmd/generate_changelog/changelog.db | Bin 3514368 -> 3526656 bytes cmd/generate_changelog/incoming/1912.txt | 7 ------- nix/pkgs/fabric/version.nix | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) delete mode 100644 cmd/generate_changelog/incoming/1912.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d5b2ae3..d0e6dfb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## v1.4.367 (2026-01-03) + +### PR [#1912](https://github.com/danielmiessler/Fabric/pull/1912) by [berniegreen](https://github.com/berniegreen): refactor: implement structured streaming and metadata support + +- Feat: add domain types for structured streaming (Phase 1) +- Refactor: update Vendor interface and Chatter for structured streaming (Phase 2) +- Refactor: implement structured streaming in all AI vendors (Phase 3) +- Feat: implement CLI support for metadata display (Phase 4) +- Feat: implement REST API support for metadata streaming (Phase 5) + ## v1.4.366 (2025-12-31) ### PR [#1909](https://github.com/danielmiessler/Fabric/pull/1909) by [copyleftdev](https://github.com/copyleftdev): feat: add greybeard_secure_prompt_engineer pattern diff --git a/cmd/fabric/version.go b/cmd/fabric/version.go index 5eb636d0..b57d1d7d 100644 --- a/cmd/fabric/version.go +++ b/cmd/fabric/version.go @@ -1,3 +1,3 @@ package main -var version = "v1.4.366" +var version = "v1.4.367" diff --git a/cmd/generate_changelog/changelog.db b/cmd/generate_changelog/changelog.db index 2491cd3b774ae7420714f780f4112f293f39e782..25a1943eeb9c42e450ee9870e00c4c8e15a25b56 100644 GIT binary patch delta 65143 zcmeFa2Ygi3wm3ZJOii6cdI_0OCn05O8YKx$K!H$|o;HC{5+Ff9flN7>6uP43c zns|v4#^DHfy;Z}d*AoH?}Pk?b@o1cuf6s@`>eg% zKHGWdZ-R5n31Mx=$T`spg>owX;uQ*ocAYU*oD;n#&m1eX^_}a|xl?MY#bilMGMST1 zR)fWoX}4yYQY{8^nyZcPo!BnzIX&r*W%gc)-LDtc`}U^{6druuq%!DU3Vp2;Hj}zH zJa>U0hQ0=_U%Iv3yMA<1h!(SR+#3@2zB{R(Iz)+dIJMt}f3!C$?{lr7_qDl_vbV>~ z6-wb5-=5jOs3IO$B>Q&GNzh@rsAT0-C2XA9(Wq2Ns=Z-ze-U-+kZ(mqc*oxGc^Xj_ zaxvuF`lS0*wZh)b<#%e@;+^5E7vuj!S1-i>hpetpD8wK43im48w%6%bQ_WubxAgn< zKj@#*f203I|A>C|-p*?m=sRM$H+4!;srjd3#TS@ZND1}ZirP1eYXBv zY;UjrX?=!%mi{IEe0`;UmENo0rXQ~_#J}-)wF>iI!n<$lAJ9Lb?Wj4Sc|bE-6S;TX zmd_(Ak@_)SZwCaEy`H5AhIu^$k)jS>*PWP}#$SGsb23G1i9Yo zLHY+2+Nw(tm>T4*UWVXyZ%rA3iQbx2{b7aH>q^2@U$0b(AkABAL~ysaDo=k5u_`Bc z$5r)0IMQ1krvFUQrs~o>%+^+2F2KzGRhP{O%wG3s1f#v~_WJJ#;dD$*@k(|s`8#!B zoYxbIk3pf25Cu%e`NDU1QraWLy$QQN4i^r=+n@GM3U#f-!RyFRf9;>G@fuGJj_+Am z{&1Hhjb|-h{{jt_v3UIzUjGOUyVQwV!G%*@_$S0g;|*5`UZ3(U|1~j8aK4YoRE%tD zD|@`g{RyTOu<-zvb05TVzroH%5es@g$Hcc>@bCt;Q7cHTv7{C*E}^@w2QVSe$oWMU zW0)YhF+)$q*I($2Y1dnr4&&-M^z?^-o_-hD z(+dGT{nFo4;R+*b>8Wrzpr=0v_VjBm7|>H?U{AyOZa_~%DI=h#8ZJORRbo%~UO6U4 zfiN$zk1xAP1=&$zN0_!nZGp9ULL_W4s8q1!P)xUVxjJ9Nm3ZHvD}@PZHhWr8dTNn1 z&7Nw`&o>pO<>wcsS?s1XQ)-dTRFq*$&reUwP^^5~7yg~i_vDp{$QM$4zkRw2qNOg0 zzDGaRK~Gl~qqyP;Gv8oLbnrr!VKi4ES`F&{L~eIe|wa{!~|^@4XAwFnt@vXvJ%a$S;JQ56)8> zaXd0w)x8(Irxz@cD+npN zP$5?_3eh|mCG5pfd+;@3l}cZ(NCETQuEzSMg78xW)m_Exv3|2&C@^R+{iSdQv?ihF zh|}VG;sNnF@e#33Tq4dC?-GZIcCowIN)%O#RK=?CszEBNs;eqmrBGf_exf|8+^>9A z`LME9xmY9IsY))9O&`(1*hTa|8D&)P8 z+K@q!1(7ikA4T{gMn;5$zaCy0o*DQjHi!*Ex&KeGjsG53tieA;z0)a-7IisZmqj&I zv_ivYu|_b?u|W`*T1miIDztKr6lBT%O(EXadZ6E#R&ll4jfbhBsrhAq~)9-76k8 z&9+6gWLqhFt+H2q2hGeNlga|A4ArqQ* z+RW_(a+@2^-~q^b9*1r4tbh)s!?aleB&Wf_UBMBgGJ?j@1|zga^5uaJ+at7s$sO%E zs<1tZ_h1WN>F}zS%K8qK7$NEou?^)6;@XFH#uy>%Rau)i(4J*8>ZQ9v@zDkwKx`@t?wc9V$^LLCFxd~{aM0QXA*3&&2G`d7UX zPIR&RXYCy@tTuqM;ZU|BU_K3lhLGSxG!*{P*6yF)w=?>!N%(NKPY*yp1P)FQz&9Am zKCt?y>mYbW8ytN+?7@lL^7a@R{hoJ~M!5SvyMOBTqVZXK9%ppg`he`7lwGOq9zRLh zDaedQE;g7Drlwg6GAyS2^bB)>In9wui%*6nEw#vAU@pqH+Y2+Sj?^@Bns#vzB>UD1 zLY`K?O)&N5hUNaWHdLdum3p-DFP7D6-nj#l@Dw;&g}I>_{t4FD$mF=i9Amsg{h4 ze5+#R6ZLV?;+bT#?l(n}@)JS#qOM$*to>U1xOO@Uo*!z~YVOcz)Q8ne)oH5lR6A5N zRo#@Ipm4hI!EkH0h)toBLfeEK4_Og1Bt)n$$QG9>i78I!2NavGHNw8P17_+pIQDk) zOvPeT>A`fmJ1HKr-?2rtJl-i>d-uxLMySI47S1%8il6*ACLY$d3z$@spl_RiNi`8% zm~26IHzUhG+141NObGJekc_*ih|hH12$~rIcqhP?NmeuD&aj8IU>ncamZghE_x~`MF~Lb5 z1t$X$jD)x@0ev392$DxCjWIzH;EX4Zw**d}3V8h%L)<4;KNX7z$@+H;h@)3Bl&CSONNR)7JaZ-taEcSv;o{rkhWhBWsyPBPumY3KYD+bl(hCag z7E`gg*lI1bnr-P;o844UnC`GzEcwNDGjf?{nSt#&6m6`Z;TAW>XzoNdN&G8H%!EN( z#LOuDAf==nuk0!QM2+a%K;0J6UjNz_F+4&TR)2hlI9!-`lMGt1@;PcQ6_tvD;GFa0>JsB4VyScD1&0J_pPt98Rqm{rkSioX$7b~6&EU2 zK0^%^+N~J{W=BzRp)EhvVYQ|grdljEM^Qn(#pH0LXQUOU7N(kP`HGcKGF{QrE%-$4 zS8j~xatA&U@onX&%DtMlN(s5YNh@gH*F2`F(3h*f1j82Pvii+il%h%)2A{MFG1kBP zxU#E|U`|bSIMPsVcbKhKyUCGeO)qeyIjrUat2xzVvGH1JNAdkBh}#pJSUq675`QZE zsqv@5pB8^Q{Dt5z6n|m(3&&ps{vz?G$6plwqVabd{#xO$HU8S*uPy%C;jcaZI^eG( z{yO2WbNztrF^4)#*ru>*1}nln5tl+V;m=1-3?CPk8TL@9A?&TNl8}oLQTjHaCqwM| za?N8QuSV8{?uf{WD2><{nGoJ1>_^Suh$G>Rq02)@Y2J_gLQ@gqi>wbR(hmv?^G#`L zFNTGI;gGU5OfzXCVOkUZw|0vdTL0Xkm^am;^b1tFx+J1bd=lP%H3ly{BE)fy`zH|I zib)cse}IXh38oWtU4+#H-A}^-&iBGuPG>`>x2gP0U)FDE;Bar^C+B>j8>-yS?|ccr zQ|4j$ac;Du!NT2>5~QeN`$v55eTvOXkHb!G-cx|8H`N%%HAw5lQhng!JJ^QvFJO3= zXjo6WG}81bYSPpTAMBvCv=qu-k3oyeV6Hs1JKE#~x8$354l#PRa%NVH8Z$jheL0lr zUcs4%+Y@1)-kcy+91}iHjJ_?2im&i(rsA$V&OEb9Fp7c;_8f^x7G1^Ac!Y>bg{Y%M z)Dp-d=&AD^`jUuy#kcNDs$0)>cl~aQ*GPYn@$|D%@5VyHdxW5yFY!E9aGvmme4S_! zq>rhP=_V}@LRBxaI3$TxYRJYx5Tz?{l%V@lXgC&=WOwhzb#>ZJqjPS<;wkIjh>5TN z{aB1@?X9_bYp(upn5$)7lujTK)X?P*pHE4=o`@ZvMC};byRg(KL|QHyQB%_ zFvi)%R$u4rvQi1J4z>3}X3)fMWzHMP#5OXaj9w?V0X8vQ0!JCg9&livz6 zr76A*-yw3T4+zzSb1;|~j)dt9x4~+HRej(9LC=?Pmf?6PQ*ql`Zesq4IN~rBABm*ANIEc$Ny@_1O?cwXgcUy@@BPWEMBuqGe<^)*{kUt&r?Jq$bRYTxn zEw=3n2SXjfXJHgUDHoO#bgzXS1U=8ePHYRw=mlXbsK8DTkO~~|5Jr13j~K2~7Q(h3 zpwahShTJ$VGKq^s&EiohfQuoVdk5#9{g#-s+XvCz`AO&@_b@GH(t2oINfaD`s8tAE z!yp<*1&jUyrIg`$9X1kl{su=7YNSJqFM1WNHtru`6pvO_7ud=8+yi}a7peMpP`{e+ z-sW5V6Vfkr;A$kuBmEaRvB4ODII1jAiB+{iRXDLxpj>!wO&3!~cdJm$87|IJ=-cSG ziL>+#k@caY^n*f|L)*1os_Hkc?eeQ2dhUZGQ<>tqkTsXO?2+y7`E>$4oJ?-(%qpHh zG0-@Ni^xxD>sb|2;QT9G;)<@hT=v4o?wBhjLi7XJ18EsFPGS5PprMQ|oFDrx&{K7u zg`-@e2bk`n8pWrDYQzDCRvsPPZJh#Je zIai)*`C%f_*9aTNaP8MY07U0`6ifuA4`Di|_rq$2#c+V(Q8-J`-4!ZFQ$@E3xqRU~ z195yIoq(qv!XmD|XmI9vvVi-3(9i=1&7IDP>|HdyJp(yGCN_Lp84!-N;M;JQoIBo# zxt=(5R?nad&mA!8UcPt; zcFdv+sRkZ;gv#Cq*+rD$JOD@e!u>T|#tS5}iYZt#q&4DpKLjR3g}G00?q!MQr>6oM zA4M$gD-g92VO1(*F-(C{g05_`L?he_M+i#!kj0P36AKqhn2xvM6uwmx8KfjfSh z8(3~;0j-1+hd-i$a>>)${6QO>{egZmD35e#w2hVK-1Dk5vb-io*s-b3Fea$;n? zZi#lf`b*vLu*}FW&_v(GBnmrW%$Y99iTZNklyW=@%V<+Vn}bGoBE%O`6c!eGQa>m% z0e!=5gq=dAH6M*C`Dg=z*Uoflf+OFed)s9I!#{XQaibbcONwVAtrfn;Vp=L@L3Raa z{(~2g{IPmk$Q;mkl5(B0xR5ivC+12~Q2PeuO1E=a{hvBfZW1&u<;CVGoI1=GVW{l$ z#aW2{4A(i&NXRDW{u7iDl-k24g3i|=w}A>ezkth_p>ZWKWzjE?P*Bc|?7m&3n74Ph)C zdiufHMNHLV7%r11KpYm)RLK(U85zNBXgo{A+znCZ2qr=nLDy<1<@7hO5uwJzRuo_3 zK5SHSz$Lop?f|9OO{DP~n2v2B$92h+Z;c|_nxN)9Rb9`SjiXJJDZy$c%l$AkTtFmM z9iWn^ay>?7lJy@7SjZJpkN2#G@X=`a6yo#^5gXC|s*8%9tZXAxLQzy~&$bblBELWh z{v^Iw3E|@+jzmPEi7pF6DB!iI*dloR1ED9*B?ZLc6toDgE=0r4de(%huCNm$g+zA} zjt2Fxsy&3?MlnSXa9{T9PoQzghFO>?N=G5#6P`V?7`vu5sYlXk2>+DpiZ~m2Hpr^o z9SiL7q7;eIHe5%^7%vn=(_68D6KmW8masu|Yr_5*WD|7a>qXH00Bqv?IrzjG!!oWk zdJ{z@xfgTdObn}bR~6w=EH;{5^Gkgi+xVkhO&QgZ^Ih^%`&;1q* zZ;wM+C0qTbT_8=s^)$Yz)QBrprvDUaSk7Odk357*U;k30w$Nft6Wm^$FoZ}Nh0~BO zskZ3^wI@3C_x+x|=I!y-vlX zzR=hi@4D+?Bb9QOLascxuR|$U8;;X~Ua3WJgwtc7?0X)M_ZZEV;cfBZdOnoNM29cp zG(#mtvq{V4%wJL{^PiB7^>9GjK|?G}SPS1x1Y())Cm@%qc(OUO@+mfh0z`ixB=!(I zi%EO9wQSv5wr(w3|K(*XCDs%b8<~JXe&3-Z6W6YC3~w70YS3@fo(=IuM5$jCH$dm? z*kmzu2Mo`SO%!ouTbv!6pb^l|S0qb!*|AnQGlHZJ*M|_dRZZ{n3$Q0jY!CWYVrzWO zpZ0A&fXwC#*qMXuq^c7xS0a`AJDkD`yj40fp(lbOMdTHv`1zl?czk) zxj0J5Hk$c18zx-$@SXV*+acs2lg1N?#DJ#qou;$Qv!8-a?Wt9_1=?;WBAuT@^dMq_ zA3-)j=@gW4`c=q&oC>%@;V5Oe2f$^5o_|8`!3do{z=0Bxr+{b+KF!Ed;oHs$Zov2y~CW7t> zFrA?1C&=Og&hOy>7x)a$5_G9>IpJ}8m+`H;Et$sPEGIVIMz$)~4{$P*kUJZ2J*2X3 znPD%FH)C1n4!H*hNs@E*hFRNq6fQ%_vveVq;dz+G&^lpZc4OS8ub z7c-cyPeJoEQyL3#SWzSWnTs8`n9UjkA?F4`IT{Sd-`~gHc!lNACpVKNm*x(ETeX%pcG)<$f6|iFEfzkhOzJ zZv&U`0;lT-Tx@1Fi43j{&@d`C={9LJnR{=^k2sfZ$&W(SE&1_(T7E>Xv3OrztSTyW zEJlo|vT50asClttG>Y#uj|p*5G%t3DsCW&{7rus9lJcbf^w!>NFpf~gs{hT#VhU9W zkUO7PkQyo(wnBzS9L@b1oT3cr7;Ji+GYVkGH++$dYB*g;(_qvy#Ee|)n6Vu8k&VJ5 zo0a!V?3a^;`_U^{Gw2K(cTjoH4_v{|ZOWF%~)IVCOXQ4pk*XbOmxix6HG4 zjntu{w++fLPn2Fm`v4K(dLMGlB1#5s=zmU3LPFXy;^Q;P7vPq)$mo%sG2xQe`E?Bm zm~dX=VrwT7BlN7qMTWa`8;TH2p6ry_{BAp{$U8P*x;GvZl57XkhooS_%?rNIypxce z24NAAb{tFuUEiakPtb%~Ji@AMI6%03->N``d~ZKw_vyzq5C&< z`A`}aJx+fKI}mClSzRCfoSr%s%PpB@J46+3mtj<+Az>#!r{CzdZ|hcUQJM%Rc?!7Y zDUjTWBnek*=&_WrZs(HccOX*F8Ah5v*oX;NKTgco(;_MzK+74@R5bvimLYV$4Os-G zPteRmFa$Odbo~b$A?R5H**2ocV@GotT~z5|)~B4a1XX>0gnPMxGgH|-B~PrwLv_@& zEI4IfAz4ZK8RB@>N1+LVJGm4UX}WNoLxW&!Qdif|&|5<4Eg|)mkoy0mkSa=}_pOb^ z?Xe`LVzkU4h}<1p5w9<&;8KjW6x6+y<8>!=og!-@N+av_+afmV+i2RNJE0-$t?c zxzg_#_rp0(5bCLA7nlfoTETQq{|#0%^ufGARM0gV&QgZ^dtCJ>Lo&ed7m-943qG)W zHK{mKGB<0^=}qg)eNc);kuu=i+~vF;%jWvgy*Q|{7A6m7Y`AliNpw|0$qLHxybKrr zOq9(7!%Ng~9~ec@a~zg4jE5Zrr87`DoS)rMZe?9r7(K2CPDEcK%e{0Kqe7{O^DEAE ze$|=C`!g#ap){0ono6zH8dQIO^R|K zCl&LSw0le1y(R7bzgpTAT|@UBj}@c358`cjxRIhEEK_?Rq$uRo@J3;$_AEN)SBEZF zmEo@H@1X0MShptP2yUnT4s}%(GmV%}SOx6NiPgK9Lp_7uRN`aLqHK;(!eA_dRm0Ge zLpR%zHDDGXDlgD~M9} z4s=fwrP4QyX<9`%(o_}3iCyoJ;ne+iP8cq*F*FgKqDVkhJ9PXJL0_Y-)k=t-M;|?A zNN=K#o?vG<%LQEMP-LF}7##VHE}ZYdQ6^KGz=*S^($IRsQ8i?W($JMg7@hxs9Ub|i z39Zc3FKHN8Ncos$jj`y$W5l1K{*5iVVo}{h=&VO=lOQgj1YL*+p~fu-tu_v!IpLNS z@F*{Zhq@~nuX8l(vUkFcUzyH#(aKBhyY5G~Bt5q(9hd93i`CLNPRuW2V|61ciTuE2 zr|h&8*5@pcd5KZ&M+YX6;z4gcLg^&>rxCjI&|6PwEo{Oe!KN%QF_{!T=~Hx)(w(m% z;XFd;?=X>|r#&=Yrm^tkbMpuHu(4mZYeYwo1;PCi`XG63e#_?CsmZv#aozIKiLW^?N;IhM!smK=+7>y{k*zd()^-N#=r2nPHn4!cWmXS&W{SkZ2f zy0n+w?1^g9MQ8<0)P ze!94?$YAQ8#c##MathM-d;zn%VhK+l&W!sh1T$UT;cd#49^%ZyGuh%64^J&-yVW9y zE@BJVU3~l0PO=?(WKH9Y*A_22KZCOFRMeA&+Y*Sd9LOdpJ&!jiT?v~w{Z}|j(D_f8 zK7%S$#X|2MQ~;y4<}!vwX!YdA^0+Y2l%7mV+)v?a?&Uah zsl%SGxJc4WRdB)V&Fp7x#Ocdp$aZjuMn610&JDOk_-HD&rtg+%gX zE)e|)hko6OUI#HTUU0u1s=p<4-V!=*37!A_LMOhztM+9Z#3)^Zf;PzO%R!fG=-Vao z3+-xES@<|1S1IY9QXLg`sy5-i?Mz)K^Cybm|tMPLnAE^tJUbPX*>oz6WKI0wDQ;|=#$(7TFwm^7d9y|0g4yy@D z3CNDQ;5Zx>8XtEGe$9nStcI*rJWdmFha#^S1>C}#<77T|P2mK64FX5P#)<4JWYBXx z&xzO?3b}F5hcA23D0<%E+~12xS#f=WOrKhnG;nbuHD&|DBqHY>TqT&CL$I7O+^@n8 zg02TqF5nwF+>A(cI{%J~Gvi2wlF3-a6OGPdrt?Q`s^L;E8j1IC|0VZpD(>oJN=o_m zd!ZDPB*|;tu{pG0dsg$Ed9RVC>3jw^{}Bc85H*!3z`!Gd&R=mKA2s(HZl5DK4>uv= z`r=9E$`>DDP5aM~FpVnZ;Mmb1Rz*O=8YXTd7c;f888J}kOG@1A7dV8fc-$IFNZbM= zd9)qHiF)RsmymKjlQ{R#S);M9;66=i;7y};KHj1d-V!N2w?s-78E=V{_|4k?3nC@5 zzqj|zGpG!mM+%h+p;BKSaU?PU_dzTVe;z+&;z5Ni3Ij{KtThZ89yw9$gUXv-J3Yjw zX{#Tkeo?+5^f@HSg=U(N|p}O2fiJE^19;xTXSq zj%Wqdx8XH%t>KXGgM;yA51a7{Z}I~)LX{Ctts}mbjO#Lp_e0^m+Em7`h=<_^rA?aSujrI~pbx-8P(ZRfNNH$O=-%l<)shICfNt2PvAz>5YarZ*!B=b~O8hnN)=`QNL_p?Os7}r^*;y}xN zNF@=a$355xJ*{yMHl@4Z9&Ci}t+)r9@&SowVr!w(Lv-UW$oy%ImYNt{*1=Y^+LUl& z)UvKboRbrqN07=by?`D)F8>qfmR<>=5$no{d%tG)-pf$K^h=we<`r7sTx)QMsP#L+ z@G!yYxDT5eza2*m2gV&m)qM?55GpzLXx%ni=v+H+KQfc+L01{0szt9KjY$>Pf&8@A zM51g^Z(7B1O?D=RK0SoRT5;mgSyEu#=h4?nSfm;FO$h3ROSUVYu8XI>;j;QDk@qX^ z%O)7+TRQ_wI}hT%Y)m^}#(micT@mQarP@`p2R1K-%(R{%_}C0dcF()i;>~_2NvP_< z1e%YMb;C296ZxsMeZ<`xUF+QEUFch<3y%`NG=T)TXX8gBXzBKRj9;uUB=wPKg-p5W zHl15S^|xf*Te9vgS@(Zf*3JGe$hx?7YAAkOg!cL3?%wd-h7Lj-=(*dFDq>vEwB3fd z4nIZKL?%RR40|i|r1n7Q4y`HTNQh6}Tl}g1;oXMc@Y^Hbp{AlD{v>OGt3F6TcH+eE zSBDZWtqR5Mu*Akjprw!&QmF#>dJ%tdZbwHA^T#|?V0eukj`1^C)-x94XAoAk#`qb6 z12KLEp<9bf6moD$=A(yqbs{b{m$_KnZ?t~8Vqnsru%z@b)FRY)WKDAPWeNy#4?)F~ zD0PqGDuym(jdi!@#9G|msByo-*IScl&2-5wL47L6`N)ALhxMf5N&_*PhFZBFIXuyI zKSt9atTLeum;2Zj4)Bc^F`9-7oI=+m^Heh!ex(J)^((iOQ%51D(i>>nqk676=p>}u z9y!qV%tm(gU4otKcr1sa>yT@I%(V}>n6!^Lv3w2fL6zoWI1RSwQerp_LeD6OLX3#| zI5b>g5}wC^8oVPt0VXXk?Iy0DUB*!&pP^NmpG8|V3NTHF(9y^hAA#vu0oQ>)p#hR_ z=}~9qi)C<q1%lyG(^E2aPb$WZ8@xFQlw5y zO0;YM9soxeyYoE8&rtd2d>aoUcprnoXcoN6g?DYDF_MO$0h$`~+>dKF7WR~3NEkww z9ql6Y(4Al7sx=L$xK^kvpd}1eCaa9~za2EFqCz4{6@$qf(*U~ThLnj}VxN##Lr1A! z41Yc%O5A_~XPA(yTOx*sXhIF4%R`FL^^V`#3(E{|)D1^h{0Z#=Rd$F^J6*pm?4fXv z{IS8X65*6)u%@m0%aDuVSA6o0fV!6eDo8G_B>^r*bId%5w~&A{g@%a0xH) zb~~=UX1NA$yEZ|6BpU&CbMBn}Y$6_vn<|N{KS4G@&jtLZF~TYpY~u7iaFp*~g3Aas zRf$}At(_zxk8CuW-;3T~%ig5HN6c!BSLYzdjykAl}c(=d9R zD@?}=D(Bn_eJotz00<|Dnx0@HD1Cq%))Bh4!)k_IaZ5Yhe;7`2P1iHH5s2ID2g5(2 z8mnLlK~FWz5(%ZW5wcEU2i#}41H#yj)PYn^WIITdlVqp(B^61`((imH|6ca)*q~E7 zVRxQ}i+@L~RcZJ!1H#@3MiG>rh2@<757JAK$QGXL+1r5HYvQR%@=|lGVku$r+(?(J^Ksdiq-JK#GdIrR&M1}16OX5!DbmO zlR>Er`oQ|TdM*dkgq~wz+t{9+!84&}Ti80G=dW;JY|oYTdE@XqSWznkF13H34cTk3=Adi5^# zlj_ZCP_I!}t1H!u)Me@!>gnpc)T7k5tFzQ;>J)V^b*#FbTCdisuBd)eT~K|gI;}dP zdQbHR4&q+bGpeoiq1nBXMR<5XuiRMudGUAg2gM3IjRE~MvlMkNG+*qk*ADFUu+WJI zXs5zEmM;Q_%s*mA+>te;*Rhb>=;%e2qVBWjb@G*`n>V-DzFec~xbknR2kNzk_#{EZ z3tL?LG^MZefDkp##E2o)+q%c&FQI;0_ud6BtMJ4L1w`eUhic@L$zbFeF`2&S9}Zpf zk_+k$YgPA)_`NvRyt8;YKKu~tnX*q{<0|^5b9cTGHGvgf)N8-#jh=`P@I!W_HCH9! zhx4hv^C>R2_U|0Sa29_23*C0D#k~bs-hD5A;+~3C$FE#8Y89SAPOI6}TL2{((=h4U5M z#=tpGVWc8AypVBMR+Ht#(+$6phf20f_F6?p&`^0E#Bb%A5!yq(?t+AoANJ1CP8;=C?P0)huf?PfolQ=Wpd+X-1woc>|ERl6PNSQ z4&vO+-*Tv?mJ_RTXq=s|apILjY&tB$k3AFGad_k+(^Zcjh{g<0JKWLF?R3B$5Om@B z9*)o*=SirPttihyLMfUYs^s{~<*|g_Rma$4KIMSHXteDxl1^||zBrGz5yobMC43=` zfy<2FeYY>;06r%ZdzhH6)g-< zHZ8GxBrPC2n-`EB^}Pr7$`mXQPY^}xPw(5q#FOvVTrn;eY zP+`mAQ+2n~X@xCkMAZ!;bj?Q=wj5wpH@M~K#jxgM(dy_dLq6}XgQ_X$IZt)y3>u3k znLWG4+H!zl-2m9M*MHhqT@I7q;bXHA^e_0&@~X=Q^PYfWSzPSOIl%~L?y#$aoR(PE zAEw~BmCYxn)%D{V$)$*RWN856zIqWHLtcUGR>| zr%E;->v;9#xNL7-I-P{o*_&dsz!_5eJT@WbN)9koF0iGW7T)X4Eu-S7~*6aEv+ z>P%ew+mBn}&a0dt1B;zVfgQ{3ePrS>nG6>(*?g>89i9&waK@v)W&9Hf@%j((NU{kl zEPmp9!})ghzLi&xT@Oh&LK66Gxyl=z z4S78*T?xz0eqr}|Na6^IW6(`HMXra%Kv>`~9c-$3E7||b#!~+J9ysZH1RT3q*9H1_ z4q&-4kaaSEA$NvXw%URn09)4yE*`gCJs9uGv1GOLNmZ^bs#=woQm@K0{dNW8>J&B% z)5ERB(e!n1;goKPYLobrZn*fi`b%M_=6%&sv5z=QyE^PG?Q}6b{CTaQ zZ=hg2&EU`-bnIHhCH0G{Y+WaHtsK6mHAPMgdq~{Cfq7?o$6tjg{oc(&ICN?3joUQu z#jVM`r-;%H+>%W4|L3^1mSjq)5I5bDs6U)#&^#Zj6$3bteTAcUu?l|-clLYdfY)vcuzB`Egw;gn|lOqMaI@8{PfUgy_1D^ za3?aU3uEy6Sd@JccOp}|JMKg#cm+ND?1W_p9k>$Nv7d!s-(`B*;8%;et=rKb&lei} zTrX8{$?|&Nk2si|!|K<^P~5$1F}la8gd{Ru^KGPQRNaOxtVjL?;V zqlBGs3A(4y&5g6Dw~DXupj;D-Z|rRpt8%a^_k1bVAuYl+Dx^q};%nMwgb%*Lp?5hz zLnGn7>eubh8=#*Fxrn~<7M*Z852N!ZDEXFfc)En1#3Q?-=aSd7vJn&0fQ}ADMd|}q zH?b#KxD^>`lytaloCoRMupbrs;mkL^<4FZovRen*C3{X4|7IxuIlW*pFOJ|5H7x zXk~)-o{+it3607>MaO)mtt7QeyI8SuNAtyV%@@z|#WKapP0cyaG+#X3eDPHC#gok! z+nX<*Xuf#7`QkCYSg2UJt@&c34xXKs_yA0rp4bVp=)Z;26Iay#FedSB)%JOosLE!$ zt3sj7z~2Z=SK;q4UL*fe-W4)PcSU!P_DOAlHb#@H2~)o*t`J4xfZ{^S-!qE;+8;HI zCyb%4_>9w1rxS0dgV<3dKc0kNQz&v-{zE4oyLuA4>9@{!6ur%^g8ST-aazp-;!h~B zz|`Y-wDlFYWs*wWSC|M>J(e6DUbSW+=aWZ!;sIwKOB>8m9OJAbT@iCD$@Jfy4T~!#Wy>L*Es^x)NY$E)1M9@%cd04
!D%A7WCMDUs6cVAzxhcI{@W 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

oaa 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

*g^GCP#w{o3(xlV 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 delta 58482 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