using System.Diagnostics; using System.Security.Cryptography; using System.Text; namespace Nexus.Api.Services; public static class OpenClawInvocationContextFactory { private const int MaxMetadataLength = 128; public static OpenClawInvocationContext Create( string? actor = null, string? idempotencyKey = null, string? correlationId = null, string? traceParent = null, bool includeIdempotencyParameter = false) { var normalizedIdempotencyKey = NormalizeOrGenerate(idempotencyKey, "idem"); var normalizedCorrelationId = NormalizeOrGenerate(correlationId, "corr"); var normalizedActor = NormalizeActor(actor); var normalizedTraceParent = NormalizeTraceParent(traceParent); return new OpenClawInvocationContext( normalizedIdempotencyKey, normalizedCorrelationId, normalizedActor, normalizedTraceParent, includeIdempotencyParameter); } public static string Hash(string value) => Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(value))); private static string NormalizeOrGenerate(string? value, string prefix) { var trimmed = value?.Trim(); if (string.IsNullOrWhiteSpace(trimmed)) return $"{prefix}_{Guid.NewGuid():N}"; if (trimmed.Length > MaxMetadataLength) throw new ArgumentException($"{prefix} metadata must not exceed {MaxMetadataLength} characters."); if (trimmed.Any(char.IsControl)) throw new ArgumentException($"{prefix} metadata must not contain control characters."); return trimmed; } private static string NormalizeActor(string? actor) { var trimmed = actor?.Trim(); if (string.IsNullOrWhiteSpace(trimmed)) return "nexus-system"; if (trimmed.Length > MaxMetadataLength) return $"sha256:{Hash(trimmed)}"; return trimmed.Any(char.IsControl) ? $"sha256:{Hash(trimmed)}" : trimmed; } private static string NormalizeTraceParent(string? traceParent) { var candidate = traceParent?.Trim(); if (!string.IsNullOrWhiteSpace(candidate)) { if (!OpenClawGatewayProtocol.IsValidTraceParent(candidate)) throw new ArgumentException("traceparent must be a valid W3C trace context.", nameof(traceParent)); return candidate; } if (Activity.Current?.Id is { } current && OpenClawGatewayProtocol.IsValidTraceParent(current)) { return current; } using var activity = new Activity("Nexus.OpenClaw.Invocation") .SetIdFormat(ActivityIdFormat.W3C); activity.Start(); return activity.Id ?? throw new InvalidOperationException("Could not create a W3C traceparent."); } }