-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Description
Summary
Add per-turn token usage logging so we can track API consumption over time, especially to measure the impact of the memory/summarization system.
Current State
- Provider responses include
Usageinfo (input/output tokens) - This data is returned but not persisted anywhere
- No way to track token consumption trends
Proposed Implementation
1. Add usage to existing LLM complete log (quick win)
In pkg/agent/loop.go around line 868, extend the "LLM call complete" log:
logger.InfoCF("agent", "LLM call complete",
map[string]interface{}{
"turn_id": opts.TurnID,
"iteration": iteration,
"duration": time.Since(llmCallStartedAt).String(),
"response_chars": len(response.Content),
"tool_calls_count": len(response.ToolCalls),
// ADD:
"input_tokens": response.Usage.PromptTokens,
"output_tokens": response.Usage.CompletionTokens,
"total_tokens": response.Usage.TotalTokens,
})2. Add dedicated usage tracker (new file)
Create pkg/agent/usage.go:
package agent
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"time"
)
type UsageEntry struct {
Timestamp time.Time `json:"ts"`
SessionKey string `json:"session"`
Model string `json:"model"`
TurnID string `json:"turn_id"`
InputTokens int `json:"input"`
OutputTokens int `json:"output"`
TotalTokens int `json:"total"`
}
var usageMu sync.Mutex
func LogUsage(configDir string, entry UsageEntry) error {
usageMu.Lock()
defer usageMu.Unlock()
f, err := os.OpenFile(
filepath.Join(configDir, "usage.jsonl"),
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer f.Close()
return json.NewEncoder(f).Encode(entry)
}3. Call after successful LLM response
After line 875 in loop.go:
if response.Usage != nil {
LogUsage(al.configDir, UsageEntry{
Timestamp: time.Now(),
SessionKey: opts.SessionKey,
Model: al.model,
TurnID: opts.TurnID,
InputTokens: response.Usage.PromptTokens,
OutputTokens: response.Usage.CompletionTokens,
TotalTokens: response.Usage.TotalTokens,
})
}Output
Creates ~/.picoclaw/usage.jsonl with JSONL entries:
{"ts":"2026-02-27T14:30:00Z","session":"discord:123","model":"claude-opus-4-6","turn_id":"turn-1","input":1500,"output":200,"total":1700}Analysis examples
# Total tokens by session
cat ~/.picoclaw/usage.jsonl | jq -s 'group_by(.session) | map({session: .[0].session, total: (map(.total) | add)})'
# Daily totals
cat ~/.picoclaw/usage.jsonl | jq -s 'group_by(.ts[:10]) | map({date: .[0].ts[:10], total: (map(.total) | add)})'
# Average input tokens per turn (measure memory system effectiveness)
cat ~/.picoclaw/usage.jsonl | jq -s '{avg_input: (map(.input) | add / length), avg_output: (map(.output) | add / length)}'Future enhancements
- Add cost calculation based on model pricing
- CLI command:
picoclaw usage --last 7d - Config option to disable logging
- Log rotation / max file size
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels