mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-17 04:15:05 +00:00
feat(usage): add event analytics dashboard
This commit is contained in:
1 parent
b4c63e4afb
commit
4002bb4c13
31 files changed
+2316
-24
No files matched your search
@@ -21,7 +21,7 @@ func (l *Loop) makeExecuteToolCall(req *RunRequest, bridgeRS *runState) func(ctx
|
||||
emitRun := makeToolEmitRun(l, req)
|
||||
return func(ctx context.Context, state *pipeline.RunState, tc providers.ToolCall) ([]providers.Message, error) {
|
||||
tc = l.normalizeToolCall(tc)
|
||||
registryName := l.resolveToolCallName(tc.Name)
|
||||
registryName := l.canonicalToolName(l.resolveToolCallName(tc.Name))
|
||||
argsJSON, _ := json.Marshal(tc.Arguments)
|
||||
slog.Info("tool call", "agent", l.id, "tool", tc.Name, "args_len", len(argsJSON))
|
||||
|
||||
@@ -34,7 +34,7 @@ func (l *Loop) makeExecuteToolCall(req *RunRequest, bridgeRS *runState) func(ctx
|
||||
|
||||
// Emit tool span start for tracing.
|
||||
toolStart := time.Now().UTC()
|
||||
toolSpanID := l.emitToolSpanStart(ctx, toolStart, tc.Name, tc.ID, string(argsJSON))
|
||||
toolSpanID := l.emitToolSpanStart(ctx, toolStart, registryName, tc.ID, string(argsJSON))
|
||||
|
||||
// Inject agent audio snapshot so TTS tool (and any future audio consumers)
|
||||
// can read agent-level voice/model config without an extra DB lookup.
|
||||
@@ -55,6 +55,7 @@ func (l *Loop) makeExecuteToolCall(req *RunRequest, bridgeRS *runState) func(ctx
|
||||
toolDuration := time.Since(toolStart)
|
||||
|
||||
l.emitToolSpanEnd(ctx, toolSpanID, toolStart, result)
|
||||
l.recordToolUsageEvent(ctx, req, registryName, tc.Name, tc.ID, tc.Arguments, toolStart, result, toolSpanID)
|
||||
|
||||
// v3 evolution metrics: record tool execution non-blocking (best-effort).
|
||||
l.recordToolMetric(ctx, req.SessionKey, registryName, !result.IsError, toolDuration)
|
||||
@@ -73,6 +74,10 @@ func (l *Loop) makeExecuteToolCall(req *RunRequest, bridgeRS *runState) func(ctx
|
||||
type toolRawResult struct {
|
||||
result *tools.Result
|
||||
duration time.Duration
|
||||
start time.Time
|
||||
spanID uuid.UUID
|
||||
toolName string
|
||||
rawName string
|
||||
}
|
||||
|
||||
// makeExecuteToolRaw wraps tool I/O only (parallel-safe, no state mutation).
|
||||
@@ -81,7 +86,7 @@ func (l *Loop) makeExecuteToolRaw(req *RunRequest) func(ctx context.Context, tc
|
||||
emitRun := makeToolEmitRun(l, req)
|
||||
return func(ctx context.Context, tc providers.ToolCall) (providers.Message, any, error) {
|
||||
tc = l.normalizeToolCall(tc)
|
||||
registryName := l.resolveToolCallName(tc.Name)
|
||||
registryName := l.canonicalToolName(l.resolveToolCallName(tc.Name))
|
||||
argsJSON, _ := json.Marshal(tc.Arguments)
|
||||
slog.Info("tool call", "agent", l.id, "tool", tc.Name, "args_len", len(argsJSON))
|
||||
|
||||
@@ -98,7 +103,7 @@ func (l *Loop) makeExecuteToolRaw(req *RunRequest) func(ctx context.Context, tc
|
||||
|
||||
// Emit tool span start (goroutine-safe: channel send only).
|
||||
start := time.Now().UTC()
|
||||
spanID := l.emitToolSpanStart(ctx, start, tc.Name, tc.ID, string(argsJSON))
|
||||
spanID := l.emitToolSpanStart(ctx, start, registryName, tc.ID, string(argsJSON))
|
||||
|
||||
// Inject agent audio snapshot (parallel path — same as sequential makeExecuteToolCall).
|
||||
if l.agentUUID != uuid.Nil {
|
||||
@@ -125,7 +130,7 @@ func (l *Loop) makeExecuteToolRaw(req *RunRequest) func(ctx context.Context, tc
|
||||
ToolCallID: tc.ID,
|
||||
IsError: result.IsError,
|
||||
}
|
||||
return msg, &toolRawResult{result: result, duration: dur}, nil
|
||||
return msg, &toolRawResult{result: result, duration: dur, start: start, spanID: spanID, toolName: registryName, rawName: tc.Name}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,20 +156,33 @@ func (l *Loop) makeProcessToolResult(req *RunRequest, bridgeRS *runState) func(c
|
||||
emitRun := makeToolEmitRun(l, req)
|
||||
return func(ctx context.Context, state *pipeline.RunState, tc providers.ToolCall, rawMsg providers.Message, rawData any) []providers.Message {
|
||||
tc = l.normalizeToolCall(tc)
|
||||
registryName := l.resolveToolCallName(tc.Name)
|
||||
registryName := l.canonicalToolName(l.resolveToolCallName(tc.Name))
|
||||
|
||||
// Extract result and timing from toolRawResult wrapper.
|
||||
var result *tools.Result
|
||||
var dur time.Duration
|
||||
var start time.Time
|
||||
var spanID uuid.UUID
|
||||
var rawName string
|
||||
if raw, ok := rawData.(*toolRawResult); ok && raw != nil {
|
||||
result = raw.result
|
||||
dur = raw.duration
|
||||
start = raw.start
|
||||
spanID = raw.spanID
|
||||
registryName = raw.toolName
|
||||
rawName = raw.rawName
|
||||
} else if r, ok := rawData.(*tools.Result); ok {
|
||||
result = r // backward compat
|
||||
}
|
||||
if result == nil {
|
||||
return []providers.Message{rawMsg}
|
||||
}
|
||||
if rawName == "" {
|
||||
rawName = tc.Name
|
||||
}
|
||||
if !start.IsZero() {
|
||||
l.recordToolUsageEvent(ctx, req, registryName, rawName, tc.ID, tc.Arguments, start, result, spanID)
|
||||
}
|
||||
|
||||
// Record tool metrics (non-blocking, best-effort).
|
||||
l.recordToolMetric(ctx, req.SessionKey, registryName, !result.IsError, dur)
|
||||
|
||||
Reference in new issue
Block a user