Skip to content

Instantly share code, notes, and snippets.

@Andrew-Chen-Wang
Created February 25, 2026 21:43
Show Gist options
  • Select an option

  • Save Andrew-Chen-Wang/f548c0390f9bcf882a45ced409ad02ad to your computer and use it in GitHub Desktop.

Select an option

Save Andrew-Chen-Wang/f548c0390f9bcf882a45ced409ad02ad to your computer and use it in GitHub Desktop.
Automatically add tracing to OpenAI Agents JS if you use openai package directly
import { getGlobalTraceProvider, setTracingDisabled, withTrace } from "@openai/agents"
import { Agent, run } from "@openai/agents"
import { openai } from "@scraper/utils/openai"
import { zodTextFormat } from "openai/helpers/zod"
import { afterAll, beforeAll, describe, expect, it } from "vitest"
import { z } from "zod"
const testSchema = z.object({
randomNumber: z.number(),
})
describe("openai utils test", () => {
beforeAll(() => {
setTracingDisabled(false)
})
afterAll(async () => {
await getGlobalTraceProvider().forceFlush()
})
it("should create trace with openai.response.parse", async () => {
const result = await withTrace(
"Test trace should create trace with openai.response.parse",
async () => {
const testAgent = new Agent({
name: "TestOpenAITraceAgent",
model: "gpt-5-nano",
instructions: "Output a random number between 1-10",
outputType: testSchema,
})
await run(testAgent, "Output now", { maxTurns: 1 })
return openai.responses.parse({
model: "gpt-5-nano",
input: [{ role: "user", content: "Output a random number between 1-10" }],
text: { format: zodTextFormat(testSchema, "testSchema") },
})
},
)
expect(result.output_parsed?.randomNumber).toBeTypeOf("number")
})
it("should not crash when no trace is available", async () => {
const result = await openai.responses.parse({
model: "gpt-5-nano",
input: [{ role: "user", content: "Output a random number between 1-10" }],
text: { format: zodTextFormat(testSchema, "testSchema") },
})
expect(result.output_parsed?.randomNumber).toBeTypeOf("number")
})
})
import { getCurrentTrace, withResponseSpan } from "@openai/agents"
import OpenAI from "openai"
const TRACED_METHODS = new Set(["parse", "stream", "compact", "cancel"])
export function createTracedOpenAI(options?: ConstructorParameters<typeof OpenAI>[0]): OpenAI {
const client = new OpenAI(options)
const tracedResponses = new Proxy(client.responses, {
get(target, prop: string | symbol) {
const value = Reflect.get(target, prop, target) as unknown
if (typeof value === "function" && typeof prop === "string" && TRACED_METHODS.has(prop)) {
return (...args: unknown[]) => {
if (!getCurrentTrace()) {
return (value as (...a: unknown[]) => unknown).apply(target, args)
}
return withResponseSpan(async (span) => {
const response = await (value as (...a: unknown[]) => unknown).apply(target, args)
if (response && typeof response === "object" && "id" in response) {
span.spanData.response_id = (response as { id: string }).id
}
return response
})
}
}
return typeof value === "function"
? (value as (...a: unknown[]) => unknown).bind(target)
: value
},
})
return new Proxy(client, {
get(target, prop: string | symbol) {
if (prop === "responses") return tracedResponses
const value = Reflect.get(target, prop, target) as unknown
return typeof value === "function"
? (value as (...a: unknown[]) => unknown).bind(target)
: value
},
})
}
export const openai = createTracedOpenAI({ timeout: 120_000 })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment