@@ -66,6 +66,7 @@ CREATE TABLE IF NOT EXISTS usage_log (
6666 reasoning_tokens INTEGER NOT NULL DEFAULT 0,
6767 cost_usd REAL NOT NULL DEFAULT 0,
6868 latency_ms INTEGER NOT NULL DEFAULT 0,
69+ turn_latency_ms INTEGER NOT NULL DEFAULT 0,
6970 success INTEGER NOT NULL DEFAULT 1,
7071 error_class TEXT NOT NULL DEFAULT '',
7172 request_id TEXT NOT NULL DEFAULT '',
@@ -76,6 +77,18 @@ CREATE TABLE IF NOT EXISTS usage_log (
7677CREATE INDEX IF NOT EXISTS idx_usage_ts_model ON usage_log(ts, model_id);
7778CREATE INDEX IF NOT EXISTS idx_usage_chat_ts ON usage_log(chat_id, ts);
7879CREATE INDEX IF NOT EXISTS idx_usage_user_msg ON usage_log(user_message_id);
80+
81+ CREATE TABLE IF NOT EXISTS tool_call_log (
82+ id INTEGER PRIMARY KEY AUTOINCREMENT,
83+ ts DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
84+ chat_id INTEGER NOT NULL DEFAULT 0,
85+ user_msg_id INTEGER,
86+ tool_name TEXT NOT NULL,
87+ latency_ms INTEGER NOT NULL DEFAULT 0,
88+ success INTEGER NOT NULL DEFAULT 1,
89+ error_text TEXT NOT NULL DEFAULT ''
90+ );
91+ CREATE INDEX IF NOT EXISTS idx_tool_call_chat_ts ON tool_call_log(chat_id, ts);
7992`
8093
8194const (
@@ -97,10 +110,11 @@ func NewSQLite(path string) (*SQLite, error) {
97110 return nil , fmt .Errorf ("init schema: %w" , err )
98111 }
99112 // Migrations for existing databases
100- db .Exec (`ALTER TABLE messages ADD COLUMN parts TEXT` ) //nolint:errcheck
101- db .Exec (`ALTER TABLE messages ADD COLUMN embedding BLOB` ) //nolint:errcheck
102- db .Exec (`ALTER TABLE model_capabilities ADD COLUMN score REAL NOT NULL DEFAULT 0` ) //nolint:errcheck
103- db .Exec (`ALTER TABLE usage_log ADD COLUMN cost_usd REAL NOT NULL DEFAULT 0` ) //nolint:errcheck
113+ db .Exec (`ALTER TABLE messages ADD COLUMN parts TEXT` ) //nolint:errcheck
114+ db .Exec (`ALTER TABLE messages ADD COLUMN embedding BLOB` ) //nolint:errcheck
115+ db .Exec (`ALTER TABLE model_capabilities ADD COLUMN score REAL NOT NULL DEFAULT 0` ) //nolint:errcheck
116+ db .Exec (`ALTER TABLE usage_log ADD COLUMN cost_usd REAL NOT NULL DEFAULT 0` ) //nolint:errcheck
117+ db .Exec (`ALTER TABLE usage_log ADD COLUMN turn_latency_ms INTEGER NOT NULL DEFAULT 0` ) //nolint:errcheck
104118 return & SQLite {db : db }, nil
105119}
106120
@@ -720,12 +734,12 @@ func (s *SQLite) PutUsage(ctx context.Context, u llm.UsageLog) (int64, error) {
720734 INSERT INTO usage_log (
721735 provider, model_id, role, chat_id,
722736 prompt_tokens, completion_tokens, cached_prompt_tokens, reasoning_tokens,
723- cost_usd, latency_ms, success, error_class, request_id, tool_call_count,
737+ cost_usd, latency_ms, turn_latency_ms, success, error_class, request_id, tool_call_count,
724738 user_message_id, assistant_message_id
725- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` ,
739+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )` ,
726740 u .Provider , u .ModelID , u .Role , u .ChatID ,
727741 u .PromptTokens , u .CompletionTokens , u .CachedPromptTokens , u .ReasoningTokens ,
728- u .Cost , u .LatencyMs , boolToInt (u .Success ), u .ErrorClass , u .RequestID , u .ToolCallCount ,
742+ u .Cost , u .LatencyMs , u . TurnLatencyMs , boolToInt (u .Success ), u .ErrorClass , u .RequestID , u .ToolCallCount ,
729743 nullableInt64 (u .UserMessageID ), nullableInt64 (u .AssistantMessageID ))
730744 if err != nil {
731745 return 0 , fmt .Errorf ("put usage: %w" , err )
@@ -742,6 +756,26 @@ func (s *SQLite) UpdateAssistantMessageID(ctx context.Context, usageID, msgID in
742756 return nil
743757}
744758
759+ func (s * SQLite ) UpdateTurnLatencyMs (ctx context.Context , usageID int64 , ms int ) error {
760+ _ , err := s .db .ExecContext (ctx ,
761+ `UPDATE usage_log SET turn_latency_ms = ? WHERE id = ?` , ms , usageID )
762+ if err != nil {
763+ return fmt .Errorf ("update usage turn_latency_ms: %w" , err )
764+ }
765+ return nil
766+ }
767+
768+ func (s * SQLite ) PutToolCall (ctx context.Context , t llm.ToolCallLog ) error {
769+ _ , err := s .db .ExecContext (ctx , `
770+ INSERT INTO tool_call_log (chat_id, user_msg_id, tool_name, latency_ms, success, error_text)
771+ VALUES (?, ?, ?, ?, ?, ?)` ,
772+ t .ChatID , nullableInt64 (t .UserMsgID ), t .ToolName , t .LatencyMs , boolToInt (t .Success ), t .ErrorText )
773+ if err != nil {
774+ return fmt .Errorf ("put tool call: %w" , err )
775+ }
776+ return nil
777+ }
778+
745779func (s * SQLite ) UsageTotals (ctx context.Context , since time.Time ) (llm.UsageTotals , error ) {
746780 var t llm.UsageTotals
747781 err := s .db .QueryRowContext (ctx , `
0 commit comments