Skip to content

feat(attachments): add json attachment uploads#125

Open
Abhijeet Prasad (AbhiPrasad) wants to merge 1 commit intomainfrom
abhi-feat-json-attachments-api
Open

feat(attachments): add json attachment uploads#125
Abhijeet Prasad (AbhiPrasad) wants to merge 1 commit intomainfrom
abhi-feat-json-attachments-api

Conversation

@AbhiPrasad
Copy link
Copy Markdown
Member

Add a public JSON attachment API that serializes JSON, stores an attachment reference on an OpenTelemetry span, and uploads the JSON payload in the background. The upload queue is owned by the Braintrust client and is flushed or shut down with the configured tracer provider/span processor.

New public API:

Initialize Braintrust with a tracer provider and the normal client options:

tp := sdktrace.NewTracerProvider()
defer tp.Shutdown(context.Background())

bt, err := braintrust.New(tp,
    braintrust.WithAPIKey(os.Getenv("BRAINTRUST_API_KEY")),
    braintrust.WithProject("my-project"),
)
if err != nil {
    log.Fatal(err)
}

tracer := bt.Tracer("my-app")

Send a JSON attachment by starting a span and passing that span to the client:

ctx, span := tracer.Start(context.Background(), "example")
defer span.End()

_, err = bt.SetJSONAttachment(ctx, span, "braintrust.input_json", map[string]any{
    "messages": []map[string]string{
        {"role": "user", "content": "Summarize this conversation."},
    },
},
    attachment.WithFilename("conversation.json"),
    attachment.WithPrettyJSON(),
)
if err != nil {
    log.Fatal(err)
}

Add a public JSON attachment API that serializes JSON, stores an attachment
reference on an OpenTelemetry span, and uploads the JSON payload in the
background. The upload queue is owned by the Braintrust client and is flushed or
shut down with the configured tracer provider/span processor.

New public API:

- (*braintrust.Client).SetJSONAttachment(ctx, span, key, data, opts...)
  serializes data as JSON, sets key on the span to a Braintrust attachment
  reference, enqueues the upload, and returns the AttachmentReference.
- trace/attachment.JSON is the JSON MIME type constant.
- trace/attachment.WithFilename(name) sets the displayed attachment filename.
- trace/attachment.WithPrettyJSON() writes indented JSON.
- trace/attachment.AttachmentReference is the public reference shape stored on
  the span.

Initialize Braintrust with a tracer provider and the normal client options:

```go
tp := sdktrace.NewTracerProvider()
defer tp.Shutdown(context.Background())

bt, err := braintrust.New(tp,
    braintrust.WithAPIKey(os.Getenv("BRAINTRUST_API_KEY")),
    braintrust.WithProject("my-project"),
)
if err != nil {
    log.Fatal(err)
}

tracer := bt.Tracer("my-app")
```

Send a JSON attachment by starting a span and passing that span to the client:

```go
ctx, span := tracer.Start(context.Background(), "example")
defer span.End()

_, err = bt.SetJSONAttachment(ctx, span, "braintrust.input_json", map[string]any{
    "messages": []map[string]string{
        {"role": "user", "content": "Summarize this conversation."},
    },
},
    attachment.WithFilename("conversation.json"),
    attachment.WithPrettyJSON(),
)
if err != nil {
    log.Fatal(err)
}
```

Use json.RawMessage when the JSON is already encoded. Passing a raw []byte to
SetJSONAttachment follows encoding/json behavior and produces a base64 JSON
string instead of embedding the bytes as JSON.
@AbhiPrasad Abhijeet Prasad (AbhiPrasad) marked this pull request as ready for review May 1, 2026 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant