mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 02:14:39 +00:00
* feat(collaboration): isolate delegated artifacts and child runs Isolate delegated inputs and outputs behind secure artifact exchange lifecycles. Scope Agent Link tasks by tenant and root agent, and enforce delegation spawn-tree boundaries. Add process-wide child-run admission and preserve logical media paths across native, MCP, and sandbox execution. * fix(collaboration): harden delegated task isolation Enforce tenant and root-agent task scope across migrations and stores. Add exactly-once async completion delivery, delegated sandbox boundaries, and confined artifact and media recovery across runtime surfaces. * fix(collaboration): recover interrupted async tasks * fix(collaboration): normalize persisted child-run status --------- Co-authored-by: ntduc <ntduc@cpp.ai.vn>
115 lines
3.0 KiB
Go
115 lines
3.0 KiB
Go
package tracing
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
type redactorContextKey struct{}
|
|
|
|
// TextRedactor removes runtime-only values before they cross a trace, event, or
|
|
// persistence boundary. It must be deterministic and safe to call repeatedly.
|
|
type TextRedactor func(string) string
|
|
|
|
// WithTextRedactor adds a redactor while preserving any boundary installed by
|
|
// an outer run.
|
|
func WithTextRedactor(ctx context.Context, redactor TextRedactor) context.Context {
|
|
if redactor == nil {
|
|
return ctx
|
|
}
|
|
if outer := textRedactorFromContext(ctx); outer != nil {
|
|
inner := redactor
|
|
redactor = func(value string) string {
|
|
return inner(outer(value))
|
|
}
|
|
}
|
|
return context.WithValue(ctx, redactorContextKey{}, redactor)
|
|
}
|
|
|
|
func textRedactorFromContext(ctx context.Context) TextRedactor {
|
|
if ctx == nil {
|
|
return nil
|
|
}
|
|
redactor, _ := ctx.Value(redactorContextKey{}).(TextRedactor)
|
|
return redactor
|
|
}
|
|
|
|
func RedactText(ctx context.Context, value string) string {
|
|
return RedactTextWith(textRedactorFromContext(ctx), value)
|
|
}
|
|
|
|
func RedactTextWith(redactor TextRedactor, value string) string {
|
|
if redactor == nil || value == "" {
|
|
return value
|
|
}
|
|
return redactor(value)
|
|
}
|
|
|
|
// RedactValue preserves the common payload shapes used by agent events and
|
|
// trace metadata while redacting every contained string.
|
|
func RedactValue(ctx context.Context, value any) any {
|
|
return RedactValueWith(textRedactorFromContext(ctx), value)
|
|
}
|
|
|
|
func RedactValueWith(redactor TextRedactor, value any) any {
|
|
if redactor == nil || value == nil {
|
|
return value
|
|
}
|
|
switch typed := value.(type) {
|
|
case string:
|
|
return redactor(typed)
|
|
case json.RawMessage:
|
|
return json.RawMessage(redactor(string(typed)))
|
|
case []byte:
|
|
return []byte(redactor(string(typed)))
|
|
case map[string]string:
|
|
copyValue := make(map[string]string, len(typed))
|
|
for key, item := range typed {
|
|
copyValue[key] = redactor(item)
|
|
}
|
|
return copyValue
|
|
case map[string]any:
|
|
copyValue := make(map[string]any, len(typed))
|
|
for key, item := range typed {
|
|
copyValue[key] = RedactValueWith(redactor, item)
|
|
}
|
|
return copyValue
|
|
case []string:
|
|
copyValue := make([]string, len(typed))
|
|
for i, item := range typed {
|
|
copyValue[i] = redactor(item)
|
|
}
|
|
return copyValue
|
|
case []any:
|
|
copyValue := make([]any, len(typed))
|
|
for i, item := range typed {
|
|
copyValue[i] = RedactValueWith(redactor, item)
|
|
}
|
|
return copyValue
|
|
default:
|
|
return value
|
|
}
|
|
}
|
|
|
|
func RedactSpan(ctx context.Context, span store.SpanData) store.SpanData {
|
|
redactor := textRedactorFromContext(ctx)
|
|
if redactor == nil {
|
|
return span
|
|
}
|
|
span.Name = redactor(span.Name)
|
|
span.Error = redactor(span.Error)
|
|
span.InputPreview = redactor(span.InputPreview)
|
|
span.OutputPreview = redactor(span.OutputPreview)
|
|
if len(span.Metadata) > 0 {
|
|
span.Metadata = json.RawMessage(redactor(string(span.Metadata)))
|
|
}
|
|
return span
|
|
}
|
|
|
|
func RedactSpanUpdates(ctx context.Context, updates map[string]any) map[string]any {
|
|
redacted, _ := RedactValue(ctx, updates).(map[string]any)
|
|
return redacted
|
|
}
|