2026-09-24 02:31:37 +00:00
|
|
|
package processreport
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"time"
|
|
|
|
|
|
2026-10-11 01:40:38 +00:00
|
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/core/reporting"
|
|
|
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/framework/llm"
|
|
|
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/framework/structuredoutput"
|
2026-09-24 02:31:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func mapLLMSummary(source llm.ExecutionSummary) reporting.LLMSummary {
|
|
|
|
|
metric := func(value llm.TokenCount) reporting.TokenMetric {
|
|
|
|
|
return reporting.TokenMetric{Value: value.Value, Known: value.Known, Complete: value.Complete}
|
|
|
|
|
}
|
|
|
|
|
return reporting.LLMSummary{
|
|
|
|
|
LogicalCalls: source.LogicalCalls, ProviderAttempts: source.ProviderAttempts,
|
|
|
|
|
TransientRetries: source.TransientRetries, StructuralRepairs: source.StructuralRepairs,
|
|
|
|
|
Usage: reporting.LLMUsage{Prompt: metric(source.Usage.Prompt), Completion: metric(source.Usage.Completion), Total: metric(source.Usage.Total), Cached: metric(source.Usage.Cached), CacheWrite: metric(source.Usage.CacheWrite)},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type executionCall struct {
|
|
|
|
|
CallID uint64 `json:"call_id"`
|
|
|
|
|
Context structuredoutput.DiagnosticContext `json:"context"`
|
|
|
|
|
Prompt structuredoutput.PromptMetadata `json:"prompt"`
|
|
|
|
|
Started time.Time `json:"started"`
|
|
|
|
|
Finished *time.Time `json:"finished,omitempty"`
|
|
|
|
|
ElapsedMS int64 `json:"elapsed_ms"`
|
|
|
|
|
Failure structuredoutput.FailureKind `json:"failure,omitempty"`
|
|
|
|
|
Summary reporting.LLMSummary `json:"summary"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type executionEvent struct {
|
|
|
|
|
CallID uint64 `json:"call_id"`
|
|
|
|
|
Context structuredoutput.DiagnosticContext `json:"context"`
|
|
|
|
|
Kind string `json:"kind"`
|
|
|
|
|
RunID string `json:"run_id,omitempty"`
|
|
|
|
|
Time time.Time `json:"time"`
|
|
|
|
|
BackendID string `json:"backend_id,omitempty"`
|
|
|
|
|
ProfileID string `json:"profile_id,omitempty"`
|
|
|
|
|
Model string `json:"model,omitempty"`
|
|
|
|
|
Generation *uint64 `json:"generation,omitempty"`
|
|
|
|
|
Attempt *uint64 `json:"attempt,omitempty"`
|
|
|
|
|
Dispatched bool `json:"dispatched"`
|
|
|
|
|
CapacityWaitMS int64 `json:"capacity_wait_ms"`
|
|
|
|
|
GenerationMS int64 `json:"generation_ms"`
|
|
|
|
|
RetryDelayMS int64 `json:"retry_delay_ms"`
|
|
|
|
|
DurationMS int64 `json:"duration_ms"`
|
|
|
|
|
Outcome string `json:"outcome,omitempty"`
|
|
|
|
|
Failure string `json:"failure,omitempty"`
|
|
|
|
|
StatusCode int `json:"status_code,omitempty"`
|
|
|
|
|
RetriesExhausted bool `json:"retries_exhausted,omitempty"`
|
|
|
|
|
Attempts uint64 `json:"attempts"`
|
|
|
|
|
TransientRetries uint64 `json:"transient_retries"`
|
|
|
|
|
StructuralRepairs uint64 `json:"structural_repairs"`
|
|
|
|
|
Usage reporting.LLMUsage `json:"usage"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BuildLLMExecution serializes only safe observation fields and millisecond durations.
|
|
|
|
|
func BuildLLMExecution(snapshot llm.ObservationSnapshot) any {
|
|
|
|
|
calls := make([]executionCall, 0, len(snapshot.Calls))
|
|
|
|
|
events := make([]executionEvent, 0, len(snapshot.Events))
|
2026-09-24 15:32:13 +00:00
|
|
|
eventsByCall := make(map[uint64][]llm.ExecutionObservation, len(snapshot.Calls))
|
|
|
|
|
for _, event := range snapshot.Events {
|
|
|
|
|
eventsByCall[event.CallID] = append(eventsByCall[event.CallID], event)
|
|
|
|
|
}
|
2026-09-24 02:31:37 +00:00
|
|
|
for _, call := range snapshot.Calls {
|
2026-09-24 15:32:13 +00:00
|
|
|
group := llm.ObservationSnapshot{Calls: []llm.LogicalCall{call}, Events: eventsByCall[call.CallID]}
|
2026-09-24 02:31:37 +00:00
|
|
|
var finished *time.Time
|
|
|
|
|
if !call.Finished.IsZero() {
|
|
|
|
|
value := call.Finished
|
|
|
|
|
finished = &value
|
|
|
|
|
}
|
|
|
|
|
calls = append(calls, executionCall{CallID: call.CallID, Context: call.Context, Prompt: call.Prompt, Started: call.Started, Finished: finished, ElapsedMS: call.WallDuration.Milliseconds(), Failure: call.Failure, Summary: mapLLMSummary(llm.Summarize(group))})
|
|
|
|
|
}
|
|
|
|
|
for _, event := range snapshot.Events {
|
|
|
|
|
var generation, attempt *uint64
|
|
|
|
|
if event.Generation != 0 {
|
|
|
|
|
value := event.Generation
|
|
|
|
|
generation = &value
|
|
|
|
|
}
|
|
|
|
|
if event.Attempt != 0 {
|
|
|
|
|
value := event.Attempt
|
|
|
|
|
attempt = &value
|
|
|
|
|
}
|
|
|
|
|
events = append(events, executionEvent{CallID: event.CallID, Context: event.Context, Kind: event.Kind, RunID: event.RunID, Time: event.Time, BackendID: event.BackendID, ProfileID: event.ProfileID, Model: event.Model, Generation: generation, Attempt: attempt, Dispatched: event.Dispatched, CapacityWaitMS: event.CapacityWait.Milliseconds(), GenerationMS: event.GenerationDuration.Milliseconds(), RetryDelayMS: event.RetryDelay.Milliseconds(), DurationMS: event.Duration.Milliseconds(), Outcome: event.Outcome, Failure: event.Failure, StatusCode: event.StatusCode, RetriesExhausted: event.RetriesExhausted, Attempts: event.Attempts, TransientRetries: event.TransientRetries, StructuralRepairs: event.StructuralRepairs, Usage: mapLLMSummary(llm.ExecutionSummary{Usage: event.Usage}).Usage})
|
|
|
|
|
}
|
|
|
|
|
return struct {
|
|
|
|
|
Calls []executionCall `json:"calls"`
|
|
|
|
|
Events []executionEvent `json:"events"`
|
|
|
|
|
}{calls, events}
|
|
|
|
|
}
|