Skip to content

feat(integrations): add TypeSafe instrumentation - #777

Merged
Abhijeet Prasad (AbhiPrasad) merged 2 commits into
mainfrom
typesafe-instrumentation
Sep 17, 2026
Merged

Abhijeet Prasad (AbhiPrasad) merged 2 commits into
mainfrom
typesafe-instrumentation

Conversation

@AbhiPrasad

Copy link
Copy Markdown
Member

https://www.braintrust.dev/app/Braintrust%20SDKs/object?object_type=project_logs&object_id=65b29c05-ac12-4829-ba2c-2a4ae7f834c5&id=6df448c8-32e0-4ec0-9ee5-124ed3ae5e4d

image

Auto instrumentation:

import braintrust

braintrust.auto_instrument()

from typesafe_sdk import TypeSafeClient

logger = braintrust.init_logger(project="my-project")
client = TypeSafeClient()

Explicit client instrumentation:

from braintrust.integrations.typesafe import wrap_typesafe
from typesafe_sdk import TypeSafeClient

client = wrap_typesafe(TypeSafeClient())

Generated span tree:

Support ticket triage [task]
└── typesafe.systemOne [question]
    ├── input
    │   ├── state
    │   └── questions: category, urgency, duplicate_charge
    ├── metadata
    │   ├── provider: typesafe
    │   └── model: jev-1.13.0
    ├── output
    │   └── answers: category, urgency, duplicate_charge
    └── metrics
        ├── prompt_tokens: 380
        ├── completion_tokens: 70
        └── tokens: 450

Enable TypeSafe tracing before importing the provider:

```python
import braintrust

braintrust.auto_instrument()

from typesafe_sdk import TypeSafeClient

logger = braintrust.init_logger(project="my-project")
client = TypeSafeClient()
```

For explicit client setup, wrap an existing sync or async client:

```python
from braintrust.integrations.typesafe import wrap_typesafe
from typesafe_sdk import TypeSafeClient

client = wrap_typesafe(TypeSafeClient())
```

Calls to `system_one` emit `question` spans with allowlisted state,
question, answer, model, provider, and token usage fields. Both setup paths
preserve TypeSafe return values and exceptions.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 17, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-17T13:27:29.065207Z 5c62282 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 72055b70fc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".

Comment thread py/src/braintrust/integrations/typesafe/tracing.py
from braintrust.span_types import SpanTypeAttribute


_INSTRUMENTATION = "typesafe"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the standard TypeSafe origin name

All TypeSafe spans are emitted with the origin typesafe, while integration origins follow the <provider>-auto convention used by the other integrations. Consequently, source filters and cross-SDK dashboards looking for typesafe-auto will not match these spans; set this constant to typesafe-auto and update the corresponding assertion.

Useful? React with 👍 / 👎.


def wrap_typesafe(client: Any) -> Any:
"""Instrument a TypeSafe sync or async client in place."""
TypeSafeIntegration.setup()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Limit manual wrapping to the supplied client

When an application calls wrap_typesafe() to trace one client while other TypeSafe clients exist, this invokes global setup and patches both client classes, so calls from every instance are traced despite the helper promising in-place instrumentation of the supplied client. Use the appropriate sync or async patcher's wrap_target() on client so explicit wrapping remains instance-scoped.

Useful? React with 👍 / 👎.

`wrap_typesafe(client)` now routes sync and async instances through their
matching patchers. Explicit wrapping only traces the supplied client, while
`setup_typesafe()` remains the package-wide instrumentation path.

Set a default dummy TypeSafe credential so checked-in VCR cassettes can replay
in environments without provider secrets.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5c622822b9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".

from typesafe_sdk import AsyncTypeSafeClient

patcher = AsyncSystemOnePatcher if isinstance(client, AsyncTypeSafeClient) else SystemOnePatcher
return patcher.wrap_target(client)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid double-wrapping globally instrumented clients

When setup_typesafe() or auto_instrument() has already patched TypeSafeClient.system_one, this new instance-scoped path calls wrap_target() on a client with no instance marker and wraps the already-wrapped inherited class method again. Applications that combine global setup with wrap_typesafe() therefore emit two nested spans for every request. Check the patch marker on the class method before applying the instance wrapper, as the OpenAI integration's manual wrapping path does.

Useful? React with 👍 / 👎.

@AbhiPrasad
Abhijeet Prasad (AbhiPrasad) merged commit 8424adb into main Sep 17, 2026
83 checks passed
@AbhiPrasad
Abhijeet Prasad (AbhiPrasad) deleted the typesafe-instrumentation branch September 17, 2026 13:30
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.

2 participants