feat: add parameter preprocessing audit trail

This commit is contained in:
2026-05-12 13:54:51 +08:00
parent 9ea83be718
commit b9c9f457e9
17 changed files with 2323 additions and 28 deletions
+18
View File
@@ -488,6 +488,24 @@ type TaskAttempt struct {
FinishedAt string `json:"finishedAt,omitempty"`
}
type TaskParamPreprocessingLog struct {
ID string `json:"id"`
TaskID string `json:"taskId"`
AttemptID string `json:"attemptId,omitempty"`
AttemptNo int `json:"attemptNo,omitempty"`
ModelType string `json:"modelType,omitempty"`
PlatformID string `json:"platformId,omitempty"`
PlatformModelID string `json:"platformModelId,omitempty"`
ClientID string `json:"clientId,omitempty"`
Changed bool `json:"changed"`
ChangeCount int `json:"changeCount"`
ActualInput map[string]any `json:"actualInput,omitempty"`
ConvertedOutput map[string]any `json:"convertedOutput,omitempty"`
Changes []any `json:"changes,omitempty"`
ModelSnapshot map[string]any `json:"model,omitempty"`
CreatedAt time.Time `json:"createdAt"`
}
func (s *Store) ListPlatforms(ctx context.Context) ([]Platform, error) {
rows, err := s.pool.Query(ctx, `
SELECT id::text, provider, platform_key, name, COALESCE(internal_name, ''), COALESCE(base_url, ''), auth_type, status, priority,
+16
View File
@@ -214,3 +214,19 @@ type FinishTaskFailureInput struct {
ResponseFinishedAt time.Time
ResponseDurationMS int64
}
type CreateTaskParamPreprocessingLogInput struct {
TaskID string
AttemptID string
AttemptNo int
ModelType string
PlatformID string
PlatformModelID string
ClientID string
Changed bool
ChangeCount int
ActualInput map[string]any
ConvertedOutput map[string]any
Changes any
ModelSnapshot map[string]any
}
+98
View File
@@ -328,6 +328,47 @@ WHERE id = $1::uuid`, input.TaskID, input.AttemptNo); err != nil {
return attemptID, tx.Commit(ctx)
}
func (s *Store) CreateTaskParamPreprocessingLog(ctx context.Context, input CreateTaskParamPreprocessingLogInput) (string, error) {
actualInputJSON, _ := json.Marshal(emptyObjectIfNil(input.ActualInput))
convertedOutputJSON, _ := json.Marshal(emptyObjectIfNil(input.ConvertedOutput))
changesJSON, _ := json.Marshal(input.Changes)
if input.Changes == nil {
changesJSON = []byte("[]")
}
modelSnapshotJSON, _ := json.Marshal(emptyObjectIfNil(input.ModelSnapshot))
var attemptNo any
if input.AttemptNo > 0 {
attemptNo = input.AttemptNo
}
var id string
err := s.pool.QueryRow(ctx, `
INSERT INTO gateway_task_param_preprocessing_logs (
task_id, attempt_id, attempt_no, model_type, platform_id, platform_model_id, client_id,
changed, change_count, actual_input, converted_output, changes, model_snapshot
)
VALUES (
$1::uuid, NULLIF($2::text, '')::uuid, $3::int, NULLIF($4::text, ''),
NULLIF($5::text, '')::uuid, NULLIF($6::text, '')::uuid, NULLIF($7::text, ''),
$8, $9::int, $10::jsonb, $11::jsonb, $12::jsonb, $13::jsonb
)
RETURNING id::text`,
input.TaskID,
input.AttemptID,
attemptNo,
input.ModelType,
input.PlatformID,
input.PlatformModelID,
input.ClientID,
input.Changed,
input.ChangeCount,
string(actualInputJSON),
string(convertedOutputJSON),
string(changesJSON),
string(modelSnapshotJSON),
).Scan(&id)
return id, err
}
func (s *Store) attachTaskAttempts(ctx context.Context, items []GatewayTask) ([]GatewayTask, error) {
if len(items) == 0 {
return items, nil
@@ -354,6 +395,31 @@ func (s *Store) ListTaskAttempts(ctx context.Context, taskID string) ([]TaskAtte
return attemptsByTaskID[taskID], nil
}
func (s *Store) ListTaskParamPreprocessingLogs(ctx context.Context, taskID string) ([]TaskParamPreprocessingLog, error) {
rows, err := s.pool.Query(ctx, `
SELECT id::text, task_id::text, COALESCE(attempt_id::text, ''), COALESCE(attempt_no, 0),
COALESCE(model_type, ''), COALESCE(platform_id::text, ''), COALESCE(platform_model_id::text, ''),
COALESCE(client_id, ''), changed, change_count,
COALESCE(actual_input, '{}'::jsonb), COALESCE(converted_output, '{}'::jsonb),
COALESCE(changes, '[]'::jsonb), COALESCE(model_snapshot, '{}'::jsonb), created_at
FROM gateway_task_param_preprocessing_logs
WHERE task_id = $1::uuid
ORDER BY COALESCE(attempt_no, 0), created_at`, taskID)
if err != nil {
return nil, err
}
defer rows.Close()
items := make([]TaskParamPreprocessingLog, 0)
for rows.Next() {
item, err := scanTaskParamPreprocessingLog(rows)
if err != nil {
return nil, err
}
items = append(items, item)
}
return items, rows.Err()
}
func (s *Store) AppendTaskAttemptTrace(ctx context.Context, taskID string, attemptNo int, entry map[string]any) error {
entryJSON, _ := json.Marshal(emptyObjectIfNil(entry))
_, err := s.pool.Exec(ctx, `
@@ -459,6 +525,38 @@ func scanTaskAttempt(scanner taskScanner) (TaskAttempt, error) {
return item, nil
}
func scanTaskParamPreprocessingLog(scanner taskScanner) (TaskParamPreprocessingLog, error) {
var item TaskParamPreprocessingLog
var actualInputBytes []byte
var convertedOutputBytes []byte
var changesBytes []byte
var modelSnapshotBytes []byte
if err := scanner.Scan(
&item.ID,
&item.TaskID,
&item.AttemptID,
&item.AttemptNo,
&item.ModelType,
&item.PlatformID,
&item.PlatformModelID,
&item.ClientID,
&item.Changed,
&item.ChangeCount,
&actualInputBytes,
&convertedOutputBytes,
&changesBytes,
&modelSnapshotBytes,
&item.CreatedAt,
); err != nil {
return TaskParamPreprocessingLog{}, err
}
item.ActualInput = decodeObject(actualInputBytes)
item.ConvertedOutput = decodeObject(convertedOutputBytes)
item.Changes = decodeArray(changesBytes)
item.ModelSnapshot = decodeObject(modelSnapshotBytes)
return item, nil
}
func enrichTaskAttemptFromMetrics(item *TaskAttempt) {
if item == nil || len(item.Metrics) == 0 {
return