package adk import ( "fmt" "time" "github.com/orchard9/stemedb-go/steme" ) // parseLen converts a string lens name to steme.Lens. func parseLen(lens string) steme.Lens { switch lens { case "recency": return steme.LensRecency case "consensus": return steme.LensConsensus case "authority": return steme.LensAuthority case "vote_aware_consensus": return steme.LensVoteAwareConsensus case "trust_aware_authority": return steme.LensTrustAwareAuthority default: return steme.LensConsensus // Default to consensus } } // parseLifecycle converts a string lifecycle stage to steme.LifecycleStage. func parseLifecycle(lifecycle string) steme.LifecycleStage { switch lifecycle { case "proposed": return steme.LifecycleProposed case "under_review": return steme.LifecycleUnderReview case "approved": return steme.LifecycleApproved case "deprecated": return steme.LifecycleDeprecated case "rejected": return steme.LifecycleRejected default: return steme.LifecycleProposed // Default to proposed } } // parseSupersessionType converts a string supersession type to steme.SupersessionType. func parseSupersessionType(t string) steme.SupersessionType { switch t { case "Invalidate", "invalidate": return steme.SupersessionInvalidate case "Temporal", "temporal": return steme.SupersessionTemporal case "Refinement", "refinement": return steme.SupersessionRefinement case "RequiresReview", "requires_review": return steme.SupersessionRequiresReview case "Additive", "additive": return steme.SupersessionAdditive default: return steme.SupersessionInvalidate // Default to invalidate } } // setObjectValue sets the object value on an assertion builder based on the input type. func setObjectValue(builder *steme.AssertionBuilder, obj any) error { switch v := obj.(type) { case string: builder.WithText(v) case float64: builder.WithNumber(v) case bool: builder.WithBoolean(v) case map[string]any: // Handle ObjectValue from JSON if typeStr, ok := v["type"].(string); ok { if value, ok := v["value"]; ok { switch typeStr { case "Text": if str, ok := value.(string); ok { builder.WithText(str) } case "Number": if num, ok := value.(float64); ok { builder.WithNumber(num) } case "Boolean": if b, ok := value.(bool); ok { builder.WithBoolean(b) } case "Reference": if ref, ok := value.(string); ok { builder.WithReference(ref) } } } } default: return fmt.Errorf("unsupported object type: %T", obj) } return nil } // convertQueryResult converts a steme.QueryResult to a QueryOutput. func convertQueryResult(result *steme.QueryResult, minConfidence float32) QueryOutput { if len(result.Assertions) == 0 { return QueryOutput{ Error: "no results found", } } // Take the first result (lens already applied resolution) assertion := result.Assertions[0] // Check confidence threshold confidence := float32(assertion.Confidence) if minConfidence > 0 && confidence < minConfidence { return QueryOutput{ Value: assertion.Object.Value, Confidence: confidence, Lifecycle: string(assertion.Lifecycle), QueryID: generateQueryID(), Error: fmt.Sprintf("confidence %.2f below threshold %.2f", confidence, minConfidence), } } // Convert sources sources := make([]Source, 0, len(result.Assertions)) for _, a := range result.Assertions { sources = append(sources, Source{ Hash: a.Hash, SourceHash: a.SourceHash, Weight: float32(a.Confidence), }) } return QueryOutput{ Value: assertion.Object.Value, Confidence: confidence, Lifecycle: string(assertion.Lifecycle), Sources: sources, QueryID: generateQueryID(), } } // convertToConstraints converts query results to constraint objects. func convertToConstraints(result *steme.QueryResult) []Constraint { constraints := make([]Constraint, 0) for _, assertion := range result.Assertions { constraint := Constraint{ Subject: assertion.Subject, } // Determine if this is a must-use or forbidden constraint // based on predicate switch assertion.Predicate { case "must_use": if text, ok := assertion.Object.Value.(string); ok { constraint.MustUse = text } case "forbidden": if text, ok := assertion.Object.Value.(string); ok { constraint.Forbidden = text } } // Extract reason from parent assertion if available // (This is a simplified implementation) constraint.Reason = "Approved organizational pattern" constraints = append(constraints, constraint) } return constraints } // generateQueryID generates a unique query ID for audit trails. func generateQueryID() string { // Generate a unique query ID for audit trail // In production, this would be generated server-side return fmt.Sprintf("query_%d", time.Now().UnixNano()) } // convertTraceResult converts a steme.TraceResult to a TraceOutput. func convertTraceResult(result *steme.TraceResult) TraceOutput { queries := make([]QueryTrace, 0, len(result.Audits)) for _, audit := range result.Audits { // Extract subject and predicate from params subject := "" if audit.Params.Subject != nil { subject = *audit.Params.Subject } predicate := "" if audit.Params.Predicate != nil { predicate = *audit.Params.Predicate } // Extract lens (convert to lowercase for consistency) lens := "consensus" // Default if audit.Params.Lens != nil { lensVal := string(*audit.Params.Lens) // Convert "Consensus" -> "consensus", etc. switch lensVal { case "Recency": lens = "recency" case "Consensus": lens = "consensus" case "Authority": lens = "authority" case "VoteAwareConsensus": lens = "vote_aware_consensus" case "TrustAwareAuthority": lens = "trust_aware_authority" default: lens = "consensus" } } // Extract result value (simplified - just use hash if available) resultValue := "" if audit.ResultHash != nil { resultValue = *audit.ResultHash } // Extract contributing assertion hashes contributing := make([]string, 0, len(audit.ContributingAssertions)) for _, ca := range audit.ContributingAssertions { contributing = append(contributing, ca.AssertionHash) } queries = append(queries, QueryTrace{ QueryID: audit.QueryID, Timestamp: fmt.Sprintf("%d", audit.Timestamp), Subject: subject, Predicate: predicate, Lens: lens, Result: resultValue, Confidence: audit.ResultConfidence, Contributing: contributing, }) } return TraceOutput{ Queries: queries, } }