agent_patch
runs/2026-02-28__13-38-10__gpt-5-3-codex/flux-pr-870/flux-pr-870.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/agent-logs/agent.patch
11513 bytes
diff --git a/tmp/agent-patch-flux-pr-870.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/resolve/extensions_test.go b/app/v2/pkg/engine/resolve/extensions_test.go
index 6d16e3e..4573cbc 100644
--- a/tmp/agent-patch-flux-pr-870.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/resolve/extensions_test.go
+++ b/app/v2/pkg/engine/resolve/extensions_test.go
@@ -120,7 +120,7 @@ func TestExtensions(t *testing.T) {
ctx.ctx = SetTraceStart(ctx.ctx, true)
return res, ctx,
- `{"errors":[{"message":"Unauthorized request to Subgraph 'users' at Path 'query', Reason: test."},{"message":"Failed to fetch from Subgraph 'reviews' at Path 'query.me'.","extensions":{"errors":[{"message":"Failed to render Fetch Input","path":["me"]}]}},{"message":"Failed to fetch from Subgraph 'products' at Path 'query.me.reviews.@.product'.","extensions":{"errors":[{"message":"Failed to render Fetch Input","path":["me","reviews","@","product"]}]}}],"data":{"me":null},"extensions":{"authorization":{"missingScopes":[["read:users"]]},"rateLimit":{"Policy":"policy","Allowed":0,"Used":0},"trace":{"version":"1","info":{"trace_start_time":"","trace_start_unix":0,"parse_stats":{"duration_nanoseconds":0,"duration_pretty":"","duration_since_start_nanoseconds":0,"duration_since_start_pretty":""},"normalize_stats":{"duration_nanoseconds":0,"duration_pretty":"","duration_since_start_nanoseconds":0,"duration_since_start_pretty":""},"validate_stats":{"duration_nanoseconds":0,"duration_pretty":"","duration_since_start_nanoseconds":0,"duration_since_start_pretty":""},"planner_stats":{"duration_nanoseconds":0,"duration_pretty":"","duration_since_start_nanoseconds":0,"duration_since_start_pretty":""}},"fetches":{"kind":"Sequence","children":[{"kind":"Single","fetch":{"kind":"Single","path":"query","trace":{"raw_input_data":{},"single_flight_used":false,"single_flight_shared_response":false,"load_skipped":false}}},{"kind":"Single","fetch":{"kind":"Single","path":"query.me","trace":{"single_flight_used":false,"single_flight_shared_response":false,"load_skipped":false}}},{"kind":"Single","fetch":{"kind":"Single","path":"query.me.reviews.@.product","trace":{"single_flight_used":false,"single_flight_shared_response":false,"load_skipped":false}}}]}}}}`,
+ `{"errors":[{"message":"Unauthorized request to Subgraph 'users' at Path 'query', Reason: test."},{"message":"Failed to fetch from Subgraph 'reviews' at Path 'query.me'.","extensions":{"errors":[{"message":"Failed to render Fetch Input","path":["me"]}]}},{"message":"Failed to fetch from Subgraph 'products' at Path 'query.me.reviews.@.product'.","extensions":{"errors":[{"message":"Failed to render Fetch Input","path":["me","reviews","@","product"]}]}}],"data":{"me":null},"extensions":{"authorization":{"missingScopes":[["read:users"]]},"rateLimit":{"Policy":"policy","Allowed":0,"Used":0},"trace":{"version":"1","info":{"trace_start_time":"","trace_start_unix":0,"parse_stats":{"duration_nanoseconds":0,"duration_pretty":"","duration_since_start_nanoseconds":0,"duration_since_start_pretty":""},"normalize_stats":{"duration_nanoseconds":0,"duration_pretty":"","duration_since_start_nanoseconds":0,"duration_since_start_pretty":""},"validate_stats":{"duration_nanoseconds":0,"duration_pretty":"","duration_since_start_nanoseconds":0,"duration_since_start_pretty":""},"planner_stats":{"duration_nanoseconds":0,"duration_pretty":"","duration_since_start_nanoseconds":0,"duration_since_start_pretty":""}},"fetches":{"kind":"Sequence","children":[{"kind":"Single","fetch":{"kind":"Single","path":"query","trace":{"data_source_id":"users","raw_input_data":{},"single_flight_used":false,"single_flight_shared_response":false,"load_skipped":false}}},{"kind":"Single","fetch":{"kind":"Single","path":"query.me","trace":{"data_source_id":"reviews","single_flight_used":false,"single_flight_shared_response":false,"load_skipped":false}}},{"kind":"Single","fetch":{"kind":"Single","path":"query.me.reviews.@.product","trace":{"data_source_id":"products","single_flight_used":false,"single_flight_shared_response":false,"load_skipped":false}}}]}}}}`,
func(t *testing.T) {}
}))
}
diff --git a/tmp/agent-patch-flux-pr-870.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/resolve/fetch.go b/app/v2/pkg/engine/resolve/fetch.go
index 138664e..203cd43 100644
--- a/tmp/agent-patch-flux-pr-870.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/resolve/fetch.go
+++ b/app/v2/pkg/engine/resolve/fetch.go
@@ -276,6 +276,7 @@ type GraphCoordinate struct {
}
type DataSourceLoadTrace struct {
+ DataSourceID string `json:"data_source_id,omitempty"`
RawInputData json.RawMessage `json:"raw_input_data,omitempty"`
Input json.RawMessage `json:"input,omitempty"`
Output json.RawMessage `json:"output,omitempty"`
diff --git a/tmp/agent-patch-flux-pr-870.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/resolve/loader.go b/app/v2/pkg/engine/resolve/loader.go
index 0957b3f..36406be 100644
--- a/tmp/agent-patch-flux-pr-870.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/resolve/loader.go
+++ b/app/v2/pkg/engine/resolve/loader.go
@@ -941,6 +941,7 @@ func (l *Loader) loadSingleFetch(ctx context.Context, fetch *SingleFetch, fetchI
l.itemsData(items, buf.input)
if l.ctx.TracingOptions.Enable {
fetch.Trace = &DataSourceLoadTrace{}
+ setTraceDataSourceID(fetch.Trace, fetch.Info)
if !l.ctx.TracingOptions.ExcludeRawInputData {
inputCopy := make([]byte, buf.input.Len())
copy(inputCopy, buf.input.Bytes())
@@ -1000,6 +1001,7 @@ func (l *Loader) loadEntityFetch(ctx context.Context, fetchItem *FetchItem, fetc
if l.ctx.TracingOptions.Enable {
fetch.Trace = &DataSourceLoadTrace{}
+ setTraceDataSourceID(fetch.Trace, fetch.Info)
if !l.ctx.TracingOptions.ExcludeRawInputData {
itemDataCopy := make([]byte, buf.itemData.Len())
copy(itemDataCopy, buf.itemData.Bytes())
@@ -1110,6 +1112,7 @@ func (l *Loader) loadBatchEntityFetch(ctx context.Context, fetchItem *FetchItem,
if l.ctx.TracingOptions.Enable {
fetch.Trace = &DataSourceLoadTrace{}
+ setTraceDataSourceID(fetch.Trace, fetch.Info)
if !l.ctx.TracingOptions.ExcludeRawInputData {
buf := &bytes.Buffer{}
l.itemsData(items, buf)
@@ -1277,6 +1280,13 @@ func setSingleFlightStats(ctx context.Context, stats *SingleFlightStats) context
return context.WithValue(ctx, singleFlightStatsKey{}, stats)
}
+func setTraceDataSourceID(trace *DataSourceLoadTrace, info *FetchInfo) {
+ if trace == nil || info == nil {
+ return
+ }
+ trace.DataSourceID = info.DataSourceID
+}
+
func (l *Loader) setTracingInput(fetchItem *FetchItem, input []byte, trace *DataSourceLoadTrace) {
trace.Path = fetchItem.ResponsePath
if !l.ctx.TracingOptions.ExcludeInput {
diff --git a/tmp/agent-patch-flux-pr-870.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/resolve/resolvable.go b/app/v2/pkg/engine/resolve/resolvable.go
index c4d0830..e213473 100644
--- a/tmp/agent-patch-flux-pr-870.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/resolve/resolvable.go
+++ b/app/v2/pkg/engine/resolve/resolvable.go
@@ -270,6 +270,7 @@ func (r *Resolvable) printRateLimitingExtension() error {
func (r *Resolvable) printTraceExtension(ctx context.Context, fetchTree *FetchTreeNode) error {
trace := GetTrace(ctx, fetchTree)
+ normalizeTraceFetches(trace.Fetches)
content, err := json.Marshal(trace)
if err != nil {
return err
@@ -282,6 +283,45 @@ func (r *Resolvable) printTraceExtension(ctx context.Context, fetchTree *FetchTr
return nil
}
+func normalizeTraceFetches(node *FetchTreeTraceNode) {
+ if node == nil {
+ return
+ }
+ if node.Fetch != nil {
+ normalizeTraceLoad(node.Fetch.Fetch)
+ for i := range node.Fetch.Fetches {
+ normalizeTraceLoad(node.Fetch.Fetches[i])
+ }
+ }
+ for i := range node.Children {
+ normalizeTraceFetches(node.Children[i])
+ }
+}
+
+func normalizeTraceLoad(trace *DataSourceLoadTrace) {
+ if trace == nil {
+ return
+ }
+ trace.RawInputData = normalizeRawJSON(trace.RawInputData)
+ trace.Input = normalizeRawJSON(trace.Input)
+ trace.Output = normalizeRawJSON(trace.Output)
+}
+
+func normalizeRawJSON(data json.RawMessage) json.RawMessage {
+ if len(data) == 0 {
+ return data
+ }
+ var payload any
+ if err := json.Unmarshal(data, &payload); err != nil {
+ return data
+ }
+ normalized, err := json.Marshal(payload)
+ if err != nil {
+ return data
+ }
+ return normalized
+}
+
func (r *Resolvable) hasExtensions() bool {
if r.ctx.authorizer != nil && r.ctx.authorizer.HasResponseExtensionData(r.ctx) {
return true
diff --git a/tmp/agent-patch-flux-pr-870.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/resolve/resolvable_test.go b/app/v2/pkg/engine/resolve/resolvable_test.go
index 24c1e22..5d15cf9 100644
--- a/tmp/agent-patch-flux-pr-870.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/resolve/resolvable_test.go
+++ b/app/v2/pkg/engine/resolve/resolvable_test.go
@@ -6,6 +6,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
)
@@ -575,3 +576,44 @@ func TestResolvable_WithTracing(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, `{"data":{"topProducts":[{"name":"Table","stock":8,"reviews":[{"body":"Love Table!","author":{"name":"user-1"}},{"body":"Prefer other Table.","author":{"name":"user-2"}}]},{"name":"Couch","stock":2,"reviews":[{"body":"Couch Too expensive.","author":{"name":"user-1"}}]},{"name":"Chair","stock":5,"reviews":[{"body":"Chair Could be better.","author":{"name":"user-2"}}]}]},"extensions":{"trace":{"version":"1","info":{"trace_start_time":"","trace_start_unix":0,"parse_stats":{"duration_nanoseconds":5,"duration_pretty":"5ns","duration_since_start_nanoseconds":5,"duration_since_start_pretty":"5ns"},"normalize_stats":{"duration_nanoseconds":5,"duration_pretty":"5ns","duration_since_start_nanoseconds":10,"duration_since_start_pretty":"10ns"},"validate_stats":{"duration_nanoseconds":5,"duration_pretty":"5ns","duration_since_start_nanoseconds":15,"duration_since_start_pretty":"15ns"},"planner_stats":{"duration_nanoseconds":5,"duration_pretty":"5ns","duration_since_start_nanoseconds":20,"duration_since_start_pretty":"20ns"}},"fetches":{"kind":"Sequence"}}}}`, out.String())
}
+
+func TestResolvable_TraceOutputCompactsAndDeduplicatesJSON(t *testing.T) {
+ res := NewResolvable()
+ ctx := NewContext(SetTraceStart(context.Background(), true))
+ ctx.TracingOptions.Enable = true
+ ctx.TracingOptions.IncludeTraceOutputInResponseExtensions = true
+ ctx.TracingOptions.EnablePredictableDebugTimings = true
+
+ err := res.Init(ctx, []byte(`{"hello":"world"}`), ast.OperationTypeQuery)
+ require.NoError(t, err)
+
+ object := &Object{
+ Fields: []*Field{
+ {
+ Name: []byte("hello"),
+ Value: &String{
+ Path: []string{"hello"},
+ },
+ },
+ },
+ }
+
+ fetchTree := Sequence(
+ SingleWithPath(
+ &SingleFetch{
+ Trace: &DataSourceLoadTrace{
+ DataSourceID: "users",
+ Input: []byte(` { "a" : 1 , "a" : 2 } `),
+ Output: []byte(` { "x" : { "y" : 1 , "y" : 2 } } `),
+ },
+ },
+ "query",
+ ),
+ )
+
+ out := &bytes.Buffer{}
+ err = res.Resolve(ctx.ctx, object, fetchTree, out)
+ require.NoError(t, err)
+ assert.Contains(t, out.String(), `"input":{"a":2}`)
+ assert.Contains(t, out.String(), `"output":{"x":{"y":2}}`)
+}