Skip to content
This repository was archived by the owner on Sep 18, 2025. It is now read-only.

Commit 2af1bbb

Browse files
Merge pull request #25 from kujtimiihoxha/cleanup-logs-status
Cleanup Logs and Status
2 parents b12ca55 + 635324d commit 2af1bbb

File tree

25 files changed

+612
-329
lines changed

25 files changed

+612
-329
lines changed

cmd/root.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,6 @@ func setupSubscriptions(app *app.App) (chan tea.Msg, func()) {
107107
wg.Done()
108108
}()
109109
}
110-
{
111-
sub := app.Status.Subscribe(ctx)
112-
wg.Add(1)
113-
go func() {
114-
for ev := range sub {
115-
ch <- ev
116-
}
117-
wg.Done()
118-
}()
119-
}
120110
return ch, func() {
121111
cancel()
122112
wg.Wait()

internal/app/services.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ import (
1111
"github.com/kujtimiihoxha/termai/internal/lsp/watcher"
1212
"github.com/kujtimiihoxha/termai/internal/message"
1313
"github.com/kujtimiihoxha/termai/internal/permission"
14-
"github.com/kujtimiihoxha/termai/internal/pubsub"
1514
"github.com/kujtimiihoxha/termai/internal/session"
16-
"github.com/kujtimiihoxha/termai/internal/tui/util"
1715
)
1816

1917
type App struct {
@@ -27,16 +25,14 @@ type App struct {
2725

2826
Logger logging.Interface
2927

30-
Status *pubsub.Broker[util.InfoMsg]
3128
ceanups []func()
3229
}
3330

3431
func New(ctx context.Context, conn *sql.DB) *App {
3532
cfg := config.Get()
3633
q := db.New(conn)
37-
log := logging.NewLogger(logging.Options{
38-
Level: cfg.Log.Level,
39-
})
34+
log := logging.Get()
35+
log.SetLevel(cfg.Log.Level)
4036
sessions := session.NewService(ctx, q)
4137
messages := message.NewService(ctx, q)
4238

@@ -46,7 +42,6 @@ func New(ctx context.Context, conn *sql.DB) *App {
4642
Messages: messages,
4743
Permissions: permission.NewPermissionService(),
4844
Logger: log,
49-
Status: pubsub.NewBroker[util.InfoMsg](),
5045
LSPClients: make(map[string]*lsp.Client),
5146
}
5247

internal/config/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ type Config struct {
7070
LSP map[string]LSPConfig `json:"lsp,omitempty"`
7171

7272
Model *Model `json:"model,omitempty"`
73+
74+
Debug bool `json:"debug,omitempty"`
7375
}
7476

7577
var cfg *Config
@@ -95,8 +97,10 @@ func Load(debug bool) error {
9597
// Add defaults
9698
viper.SetDefault("data.directory", defaultDataDirectory)
9799
if debug {
100+
viper.SetDefault("debug", true)
98101
viper.Set("log.level", "debug")
99102
} else {
103+
viper.SetDefault("debug", false)
100104
viper.SetDefault("log.level", defaultLogLevel)
101105
}
102106

internal/llm/agent/agent.go

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"log"
87
"strings"
98
"sync"
109

@@ -15,8 +14,6 @@ import (
1514
"github.com/kujtimiihoxha/termai/internal/llm/provider"
1615
"github.com/kujtimiihoxha/termai/internal/llm/tools"
1716
"github.com/kujtimiihoxha/termai/internal/message"
18-
"github.com/kujtimiihoxha/termai/internal/pubsub"
19-
"github.com/kujtimiihoxha/termai/internal/tui/util"
2017
)
2118

2219
type Agent interface {
@@ -94,24 +91,13 @@ func (c *agent) processEvent(
9491
assistantMsg.AppendContent(event.Content)
9592
return c.Messages.Update(*assistantMsg)
9693
case provider.EventError:
97-
// TODO: remove when realease
98-
log.Println("error", event.Error)
99-
c.App.Status.Publish(pubsub.UpdatedEvent, util.InfoMsg{
100-
Type: util.InfoTypeError,
101-
Msg: event.Error.Error(),
102-
})
94+
c.App.Logger.PersistError(event.Error.Error())
10395
return event.Error
10496
case provider.EventWarning:
105-
c.App.Status.Publish(pubsub.UpdatedEvent, util.InfoMsg{
106-
Type: util.InfoTypeWarn,
107-
Msg: event.Info,
108-
})
97+
c.App.Logger.PersistWarn(event.Info)
10998
return nil
11099
case provider.EventInfo:
111-
c.App.Status.Publish(pubsub.UpdatedEvent, util.InfoMsg{
112-
Type: util.InfoTypeInfo,
113-
Msg: event.Info,
114-
})
100+
c.App.Logger.PersistInfo(event.Info)
115101
case provider.EventComplete:
116102
assistantMsg.SetToolCalls(event.Response.ToolCalls)
117103
assistantMsg.AddFinish(event.Response.FinishReason)

internal/llm/agent/mcp-tools.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7-
"log"
87

98
"github.com/kujtimiihoxha/termai/internal/config"
109
"github.com/kujtimiihoxha/termai/internal/llm/tools"
10+
"github.com/kujtimiihoxha/termai/internal/logging"
1111
"github.com/kujtimiihoxha/termai/internal/permission"
1212
"github.com/kujtimiihoxha/termai/internal/version"
1313

@@ -22,6 +22,8 @@ type mcpTool struct {
2222
permissions permission.Service
2323
}
2424

25+
var logger = logging.Get()
26+
2527
type MCPClient interface {
2628
Initialize(
2729
ctx context.Context,
@@ -141,13 +143,13 @@ func getTools(ctx context.Context, name string, m config.MCPServer, permissions
141143

142144
_, err := c.Initialize(ctx, initRequest)
143145
if err != nil {
144-
log.Printf("error initializing mcp client: %s", err)
146+
logger.Error("error initializing mcp client", "error", err)
145147
return stdioTools
146148
}
147149
toolsRequest := mcp.ListToolsRequest{}
148150
tools, err := c.ListTools(ctx, toolsRequest)
149151
if err != nil {
150-
log.Printf("error listing tools: %s", err)
152+
logger.Error("error listing tools", "error", err)
151153
return stdioTools
152154
}
153155
for _, t := range tools.Tools {
@@ -170,7 +172,7 @@ func GetMcpTools(ctx context.Context, permissions permission.Service) []tools.Ba
170172
m.Args...,
171173
)
172174
if err != nil {
173-
log.Printf("error creating mcp client: %s", err)
175+
logger.Error("error creating mcp client", "error", err)
174176
continue
175177
}
176178

@@ -181,7 +183,7 @@ func GetMcpTools(ctx context.Context, permissions permission.Service) []tools.Ba
181183
client.WithHeaders(m.Headers),
182184
)
183185
if err != nil {
184-
log.Printf("error creating mcp client: %s", err)
186+
logger.Error("error creating mcp client", "error", err)
185187
continue
186188
}
187189
mcpTools = append(mcpTools, getTools(ctx, name, m, permissions, c)...)

internal/llm/provider/anthropic.go

Lines changed: 44 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -159,40 +159,9 @@ func (a *anthropicProvider) StreamResponse(ctx context.Context, messages []messa
159159
attempts := 0
160160

161161
for {
162-
// If this isn't the first attempt, we're retrying
163-
if attempts > 0 {
164-
if attempts > maxRetries {
165-
eventChan <- ProviderEvent{
166-
Type: EventError,
167-
Error: errors.New("maximum retry attempts reached for rate limit (429)"),
168-
}
169-
return
170-
}
171-
172-
// Inform user we're retrying with attempt number
173-
eventChan <- ProviderEvent{
174-
Type: EventWarning,
175-
Info: fmt.Sprintf("[Retrying due to rate limit... attempt %d of %d]", attempts, maxRetries),
176-
}
177-
178-
// Calculate backoff with exponential backoff and jitter
179-
backoffMs := 2000 * (1 << (attempts - 1)) // 2s, 4s, 8s, 16s, 32s
180-
jitterMs := int(float64(backoffMs) * 0.2)
181-
totalBackoffMs := backoffMs + jitterMs
182-
183-
// Sleep with backoff, respecting context cancellation
184-
select {
185-
case <-ctx.Done():
186-
eventChan <- ProviderEvent{Type: EventError, Error: ctx.Err()}
187-
return
188-
case <-time.After(time.Duration(totalBackoffMs) * time.Millisecond):
189-
// Continue with retry
190-
}
191-
}
192162

193163
attempts++
194164

195-
// Create new streaming request
196165
stream := a.client.Messages.NewStreaming(
197166
ctx,
198167
anthropic.MessageNewParams{
@@ -213,11 +182,8 @@ func (a *anthropicProvider) StreamResponse(ctx context.Context, messages []messa
213182
},
214183
)
215184

216-
// Process stream events
217185
accumulatedMessage := anthropic.Message{}
218-
streamSuccess := false
219186

220-
// Process the stream until completion or error
221187
for stream.Next() {
222188
event := stream.Current()
223189
err := accumulatedMessage.Accumulate(event)
@@ -247,7 +213,6 @@ func (a *anthropicProvider) StreamResponse(ctx context.Context, messages []messa
247213
eventChan <- ProviderEvent{Type: EventContentStop}
248214

249215
case anthropic.MessageStopEvent:
250-
streamSuccess = true
251216
content := ""
252217
for _, block := range accumulatedMessage.Content {
253218
if text, ok := block.AsAny().(anthropic.TextBlock); ok {
@@ -270,51 +235,59 @@ func (a *anthropicProvider) StreamResponse(ctx context.Context, messages []messa
270235
}
271236
}
272237

273-
// If the stream completed successfully, we're done
274-
if streamSuccess {
238+
err := stream.Err()
239+
if err == nil {
275240
return
276241
}
277242

278-
// Check for stream errors
279-
err := stream.Err()
280-
if err != nil {
281-
var apierr *anthropic.Error
282-
if errors.As(err, &apierr) {
283-
if apierr.StatusCode == 429 || apierr.StatusCode == 529 {
284-
// Check for Retry-After header
285-
if retryAfterValues := apierr.Response.Header.Values("Retry-After"); len(retryAfterValues) > 0 {
286-
// Parse the retry after value (seconds)
287-
var retryAfterSec int
288-
if _, err := fmt.Sscanf(retryAfterValues[0], "%d", &retryAfterSec); err == nil {
289-
retryMs := retryAfterSec * 1000
290-
291-
// Inform user of retry with specific wait time
292-
eventChan <- ProviderEvent{
293-
Type: EventWarning,
294-
Info: fmt.Sprintf("[Rate limited: waiting %d seconds as specified by API]", retryAfterSec),
295-
}
296-
297-
// Sleep respecting context cancellation
298-
select {
299-
case <-ctx.Done():
300-
eventChan <- ProviderEvent{Type: EventError, Error: ctx.Err()}
301-
return
302-
case <-time.After(time.Duration(retryMs) * time.Millisecond):
303-
// Continue with retry after specified delay
304-
continue
305-
}
306-
}
307-
}
243+
var apierr *anthropic.Error
244+
if !errors.As(err, &apierr) {
245+
eventChan <- ProviderEvent{Type: EventError, Error: err}
246+
return
247+
}
308248

309-
// Fall back to exponential backoff if Retry-After parsing failed
310-
continue
249+
if apierr.StatusCode != 429 && apierr.StatusCode != 529 {
250+
eventChan <- ProviderEvent{Type: EventError, Error: err}
251+
return
252+
}
253+
254+
if attempts > maxRetries {
255+
eventChan <- ProviderEvent{
256+
Type: EventError,
257+
Error: errors.New("maximum retry attempts reached for rate limit (429)"),
258+
}
259+
return
260+
}
261+
262+
retryMs := 0
263+
retryAfterValues := apierr.Response.Header.Values("Retry-After")
264+
if len(retryAfterValues) > 0 {
265+
var retryAfterSec int
266+
if _, err := fmt.Sscanf(retryAfterValues[0], "%d", &retryAfterSec); err == nil {
267+
retryMs = retryAfterSec * 1000
268+
eventChan <- ProviderEvent{
269+
Type: EventWarning,
270+
Info: fmt.Sprintf("[Rate limited: waiting %d seconds as specified by API]", retryAfterSec),
311271
}
312272
}
273+
} else {
274+
eventChan <- ProviderEvent{
275+
Type: EventWarning,
276+
Info: fmt.Sprintf("[Retrying due to rate limit... attempt %d of %d]", attempts, maxRetries),
277+
}
313278

314-
// For non-rate limit errors, report and exit
315-
eventChan <- ProviderEvent{Type: EventError, Error: err}
279+
backoffMs := 2000 * (1 << (attempts - 1))
280+
jitterMs := int(float64(backoffMs) * 0.2)
281+
retryMs = backoffMs + jitterMs
282+
}
283+
select {
284+
case <-ctx.Done():
285+
eventChan <- ProviderEvent{Type: EventError, Error: ctx.Err()}
316286
return
287+
case <-time.After(time.Duration(retryMs) * time.Millisecond):
288+
continue
317289
}
290+
318291
}
319292
}()
320293

@@ -412,7 +385,6 @@ func (a *anthropicProvider) convertToAnthropicMessages(messages []message.Messag
412385
blocks = append(blocks, anthropic.ContentBlockParamOfRequestToolUseBlock(toolCall.ID, inputMap, toolCall.Name))
413386
}
414387

415-
// Skip empty assistant messages completely
416388
if len(blocks) > 0 {
417389
anthropicMessages = append(anthropicMessages, anthropic.NewAssistantMessage(blocks...))
418390
}

internal/llm/provider/gemini.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ import (
44
"context"
55
"encoding/json"
66
"errors"
7-
"log"
87

98
"github.com/google/generative-ai-go/genai"
109
"github.com/google/uuid"
1110
"github.com/kujtimiihoxha/termai/internal/llm/models"
1211
"github.com/kujtimiihoxha/termai/internal/llm/tools"
1312
"github.com/kujtimiihoxha/termai/internal/message"
14-
"google.golang.org/api/googleapi"
1513
"google.golang.org/api/iterator"
1614
"google.golang.org/api/option"
1715
)
@@ -242,10 +240,6 @@ func (p *geminiProvider) StreamResponse(ctx context.Context, messages []message.
242240
break
243241
}
244242
if err != nil {
245-
var apiErr *googleapi.Error
246-
if errors.As(err, &apiErr) {
247-
log.Printf("%s", apiErr.Body)
248-
}
249243
eventChan <- ProviderEvent{
250244
Type: EventError,
251245
Error: err,

internal/llm/tools/fetch.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,7 @@ func (t *fetchTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
121121
ToolName: FetchToolName,
122122
Action: "fetch",
123123
Description: fmt.Sprintf("Fetch content from URL: %s", params.URL),
124-
Params: FetchPermissionsParams{
125-
URL: params.URL,
126-
Format: params.Format,
127-
Timeout: params.Timeout,
128-
},
124+
Params: FetchPermissionsParams(params),
129125
},
130126
)
131127

0 commit comments

Comments
 (0)