on main help sign in
fix cancell
c08f5a7Kujtim Hoxha
internal/llm/provider/anthropic.go+2
@@ -92,6 +92,7 @@ func NewAnthropicProvider(opts ...AnthropicOption) (Provider, error) {
92}
92}
93
93
94func (a *anthropicProvider) SendMessages(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (*ProviderResponse, error) {
94func (a *anthropicProvider) SendMessages(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (*ProviderResponse, error) {
95+ messages = cleanupMessages(messages)
95 anthropicMessages := a.convertToAnthropicMessages(messages)
96 anthropicMessages := a.convertToAnthropicMessages(messages)
96 anthropicTools := a.convertToAnthropicTools(tools)
97 anthropicTools := a.convertToAnthropicTools(tools)
97
98
@@ -135,6 +136,7 @@ func (a *anthropicProvider) SendMessages(ctx context.Context, messages []message
135}
136}
136
137
137func (a *anthropicProvider) StreamResponse(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (<-chan ProviderEvent, error) {
138func (a *anthropicProvider) StreamResponse(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (<-chan ProviderEvent, error) {
139+ messages = cleanupMessages(messages)
138 anthropicMessages := a.convertToAnthropicMessages(messages)
140 anthropicMessages := a.convertToAnthropicMessages(messages)
139 anthropicTools := a.convertToAnthropicTools(tools)
141 anthropicTools := a.convertToAnthropicTools(tools)
140
142
internal/llm/provider/gemini.go+2
@@ -154,6 +154,7 @@ func (p *geminiProvider) extractTokenUsage(resp *genai.GenerateContentResponse)
154}
154}
155
155
156func (p *geminiProvider) SendMessages(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (*ProviderResponse, error) {
156func (p *geminiProvider) SendMessages(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (*ProviderResponse, error) {
157+ messages = cleanupMessages(messages)
157 model := p.client.GenerativeModel(p.model.APIModel)
158 model := p.client.GenerativeModel(p.model.APIModel)
158 model.SetMaxOutputTokens(p.maxTokens)
159 model.SetMaxOutputTokens(p.maxTokens)
159
160
@@ -206,6 +207,7 @@ func (p *geminiProvider) SendMessages(ctx context.Context, messages []message.Me
206}
207}
207
208
208func (p *geminiProvider) StreamResponse(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (<-chan ProviderEvent, error) {
209func (p *geminiProvider) StreamResponse(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (<-chan ProviderEvent, error) {
210+ messages = cleanupMessages(messages)
209 model := p.client.GenerativeModel(p.model.APIModel)
211 model := p.client.GenerativeModel(p.model.APIModel)
210 model.SetMaxOutputTokens(p.maxTokens)
212 model.SetMaxOutputTokens(p.maxTokens)
211
213
internal/llm/provider/openai.go+2−1
@@ -163,6 +163,7 @@ func (p *openaiProvider) extractTokenUsage(usage openai.CompletionUsage) TokenUs
163}
163}
164
164
165func (p *openaiProvider) SendMessages(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (*ProviderResponse, error) {
165func (p *openaiProvider) SendMessages(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (*ProviderResponse, error) {
166+ messages = cleanupMessages(messages)
166 chatMessages := p.convertToOpenAIMessages(messages)
167 chatMessages := p.convertToOpenAIMessages(messages)
167 openaiTools := p.convertToOpenAITools(tools)
168 openaiTools := p.convertToOpenAITools(tools)
168
169
@@ -206,6 +207,7 @@ func (p *openaiProvider) SendMessages(ctx context.Context, messages []message.Me
206}
207}
207
208
208func (p *openaiProvider) StreamResponse(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (<-chan ProviderEvent, error) {
209func (p *openaiProvider) StreamResponse(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (<-chan ProviderEvent, error) {
210+ messages = cleanupMessages(messages)
209 chatMessages := p.convertToOpenAIMessages(messages)
211 chatMessages := p.convertToOpenAIMessages(messages)
210 openaiTools := p.convertToOpenAITools(tools)
212 openaiTools := p.convertToOpenAITools(tools)
211
213
@@ -276,4 +278,3 @@ func (p *openaiProvider) StreamResponse(ctx context.Context, messages []message.
276
278
277 return eventChan, nil
279 return eventChan, nil
278}
280}
279−
internal/llm/provider/provider.go+36
@@ -52,3 +52,39 @@ type Provider interface {
52
52
53 StreamResponse(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (<-chan ProviderEvent, error)
53 StreamResponse(ctx context.Context, messages []message.Message, tools []tools.BaseTool) (<-chan ProviderEvent, error)
54}
54}
55+
56+func cleanupMessages(messages []message.Message) []message.Message {
57+ // First pass: filter out canceled messages
58+ var cleanedMessages []message.Message
59+ for _, msg := range messages {
60+ if msg.FinishReason() != "canceled" {
61+ cleanedMessages = append(cleanedMessages, msg)
62+ }
63+ }
64+
65+ // Second pass: filter out tool messages without a corresponding tool call
66+ var result []message.Message
67+ toolMessageIDs := make(map[string]bool)
68+
69+ for _, msg := range cleanedMessages {
70+ if msg.Role == message.Assistant {
71+ for _, toolCall := range msg.ToolCalls() {
72+ toolMessageIDs[toolCall.ID] = true // Mark as referenced
73+ }
74+ }
75+ }
76+
77+ // Keep only messages that aren't unreferenced tool messages
78+ for _, msg := range cleanedMessages {
79+ if msg.Role == message.Tool {
80+ for _, toolCall := range msg.ToolResults() {
81+ if referenced, exists := toolMessageIDs[toolCall.ToolCallID]; exists && referenced {
82+ result = append(result, msg)
83+ }
84+ }
85+ } else {
86+ result = append(result, msg)
87+ }
88+ }
89+ return result
90+}