package event import ( "errors" "fmt" ) var validTypes = map[string]bool{ "session.start": true, "session.end": true, "run.start": true, "run.end": true, "span.start": true, "span.end": true, "error": true, "metric.snapshot": true, "openclaw.snapshot": true, } type ValidationError struct { Field string Message string } func (e ValidationError) Error() string { return fmt.Sprintf("%s: %s", e.Field, e.Message) } func Validate(m map[string]any) error { // Check schema schema, ok := m["schema"].(map[string]any) if !ok { return ValidationError{Field: "schema", Message: "missing or invalid"} } if name, _ := schema["name"].(string); name != "agentmon.event" && name != "agentmon.openclaw" { return ValidationError{Field: "schema.name", Message: "must be 'agentmon.event' or 'agentmon.openclaw'"} } if ver, _ := schema["version"].(float64); ver != 1 { return ValidationError{Field: "schema.version", Message: "must be 1"} } // Check event event, ok := m["event"].(map[string]any) if !ok { return ValidationError{Field: "event", Message: "missing or invalid"} } if id, _ := event["id"].(string); id == "" { return ValidationError{Field: "event.id", Message: "required"} } eventType, _ := event["type"].(string) if eventType == "" { return ValidationError{Field: "event.type", Message: "required"} } if !validTypes[eventType] { return ValidationError{Field: "event.type", Message: fmt.Sprintf("invalid type '%s'", eventType)} } if event["ts"] == nil { return ValidationError{Field: "event.ts", Message: "required"} } // Source is optional for openclaw.snapshot events if eventType != "openclaw.snapshot" { source, ok := event["source"].(map[string]any) if !ok { return ValidationError{Field: "event.source", Message: "missing or invalid"} } if fw, _ := source["framework"].(string); fw == "" { return ValidationError{Field: "event.source.framework", Message: "required"} } if cid, _ := source["client_id"].(string); cid == "" { return ValidationError{Field: "event.source.client_id", Message: "required"} } if host, _ := source["host"].(string); host == "" { return ValidationError{Field: "event.source.host", Message: "required"} } } return nil } func IsValidationError(err error) bool { var ve ValidationError return errors.As(err, &ve) }