Skip to content

feat(agents): Support for OpenAI Agents#508

Merged
Murike merged 21 commits intomainfrom
feature/parity-openai-agents
Mar 20, 2026
Merged

feat(agents): Support for OpenAI Agents#508
Murike merged 21 commits intomainfrom
feature/parity-openai-agents

Conversation

@Murike
Copy link
Contributor

@Murike Murike commented Feb 27, 2026

User description

(TS SDK Parity Effort) Missing - OpenAI Agent support - sc-34519

Description

  • Support for OpenAI Agents
    • Dedicated tracing processor
    • Node data structure for better support to Agents workflow
  • Tests and documentation

Generated description

Below is a concise technical summary of the changes proposed in this PR:

graph LR
    subgraph "galileo-examples" ["galileo-examples"]
    main_("main"):::added
    triageAgent_("triageAgent"):::added
    OPENAI_AGENTS_SDK_run_("OPENAI_AGENTS_SDK.run"):::added
    GALILEO_SDK_flush_("GALILEO_SDK.flush"):::added
    weatherAgent_("weatherAgent"):::added
    OPENAI_AGENTS_SDK_tool_("OPENAI_AGENTS_SDK.tool"):::added
    OPENAI_AGENTS_SDK_Agent_("OPENAI_AGENTS_SDK.Agent"):::added
    main_ -- "main now calls run with triageAgent to orchestrate prompts" --> triageAgent_
    main_ -- "main invokes run twice to execute agent flows" --> OPENAI_AGENTS_SDK_run_
    OPENAI_AGENTS_SDK_run_ -- "run now receives triageAgent to apply instructions and handoffs" --> triageAgent_
    main_ -- "main calls flush to send traces to Galileo backend" --> GALILEO_SDK_flush_
    triageAgent_ -- "triageAgent added handoff pointing to weatherAgent for weather queries" --> weatherAgent_
    weatherAgent_ -- "weatherAgent registers get_weather tool with zod-validated parameters" --> OPENAI_AGENTS_SDK_tool_
    triageAgent_ -- "triageAgent instantiated via Agent API embedding delegation instructions" --> OPENAI_AGENTS_SDK_Agent_
    weatherAgent_ -- "weatherAgent instantiated via Agent API including tools for weather" --> OPENAI_AGENTS_SDK_Agent_
    classDef added stroke:#15AA7A
    classDef removed stroke:#CD5270
    classDef modified stroke:#EDAC4C
    linkStyle default stroke:#CBD5E1,font-size:13px
    end
    subgraph "galileo" ["galileo"]
    GalileoTracingProcessor_("GalileoTracingProcessor"):::added
    GalileoLogger_("GalileoLogger"):::modified
    extractLlmData_("extractLlmData"):::added
    parseUsage_("parseUsage"):::modified
    registerGalileoTraceProcessor_("registerGalileoTraceProcessor"):::added
    OPENAI_AGENTS_CORE_("OPENAI_AGENTS_CORE"):::added
    addGalileoCustomSpan_("addGalileoCustomSpan"):::added
    GalileoCustomSpan_("GalileoCustomSpan"):::added
    GalileoTracingProcessor_ -- "Passes statusCode and metadata when emitting spans." --> GalileoLogger_
    GalileoTracingProcessor_ -- "Sends input/output and token metrics to extractor." --> extractLlmData_
    extractLlmData_ -- "Now handles legacy 'details' for token breakdowns." --> parseUsage_
    registerGalileoTraceProcessor_ -- "Instantiates and registers processor with SDK." --> GalileoTracingProcessor_
    registerGalileoTraceProcessor_ -- "Imports addTraceProcessor to register trace processor." --> OPENAI_AGENTS_CORE_
    addGalileoCustomSpan_ -- "Uses withCustomSpan to run callback under span." --> OPENAI_AGENTS_CORE_
    addGalileoCustomSpan_ -- "Accepts GalileoSpanLike payloads for custom span injection." --> GalileoCustomSpan_
    classDef added stroke:#15AA7A
    classDef removed stroke:#CD5270
    classDef modified stroke:#EDAC4C
    linkStyle default stroke:#CBD5E1,font-size:13px
    end
Loading

Enable Galileo tracing for OpenAI Agents by wiring GalileoTracingProcessor, GalileoCustomSpan, and the supporting node/span helpers/data extraction into the SDK so every LLM/tool/workflow node emits metadata, tools, usage, and status codes before logging. Ship supporting serialization updates, exports, and dependency metadata while capturing the new flow in the published example, package updates, and exhaustive tests to confirm the agent telemetry plumbing works end-to-end.

TopicDetails
Agent SDK support Document, package, and verify the new agent flow by adding the OpenAI Agents example/peer dependencies plus comprehensive tests for serialization, span helpers, embedded tools, nodes, and the tracing processor so reviewers see how to run the feature and trust its coverage.
Modified files (12)
  • examples/openai/agents.js
  • examples/package.json
  • package-lock.json
  • package.json
  • tests/entities/serialization.test.ts
  • tests/handlers/openai-agents/custom-span.test.ts
  • tests/handlers/openai-agents/data-extraction.test.ts
  • tests/handlers/openai-agents/embedded-tool.test.ts
  • tests/handlers/openai-agents/integration.test.ts
  • tests/handlers/openai-agents/node.test.ts
  • tests/handlers/openai-agents/span-mapping.test.ts
  • tests/handlers/openai-agents/tracing-processor.test.ts
Latest Contributors(2)
UserCommitDate
Murikechore-release-Bumping-...March 14, 2026
vanessafsoares@hotmail...ci-coverage-Add-Codeco...February 03, 2026
Agent trace plumbing Instrument agent runs end-to-end by mapping OpenAI Agents spans into Galileo’s node tree, including GalileoTracingProcessor, custom span integration, data extractors, embedded tool handling, serialization helpers, usage parsing, and telemetry exports so LLM/tool/workflow nodes propagate metadata, duration, tokens, embedded tool calls, and status codes before logging.
Modified files (13)
  • src/handlers/langchain.ts
  • src/handlers/openai-agents/custom-span.ts
  • src/handlers/openai-agents/data-extraction.ts
  • src/handlers/openai-agents/embedded-tools.ts
  • src/handlers/openai-agents/index.ts
  • src/handlers/openai-agents/node.ts
  • src/handlers/openai-agents/span-mapping.ts
  • src/handlers/openai/usage.ts
  • src/index.ts
  • src/types/logging/logger.types.ts
  • src/utils/galileo-logger.ts
  • src/utils/serialization.ts
  • src/wrappers.ts
Latest Contributors(2)
UserCommitDate
Murikefeat-logging-Updated-e...February 27, 2026
pratyusha@galileo.aifeat-langchain-handler...June 26, 2025
This pull request is reviewed by Baz. Review like a pro on (Baz).

@Murike Murike changed the title Feature/parity OpenAI agents feat(agents) : Support for OpenAI Agents Feb 27, 2026
@Murike Murike force-pushed the feature/parity-openai-agents branch from 820b376 to 411618a Compare February 27, 2026 18:52
@Murike Murike changed the title feat(agents) : Support for OpenAI Agents feat(agents): Support for OpenAI Agents Feb 27, 2026
@codecov
Copy link

codecov bot commented Feb 27, 2026

Codecov Report

❌ Patch coverage is 94.93671% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.70%. Comparing base (71712e8) to head (f8111bc).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/handlers/openai-agents/index.ts 91.13% 21 Missing ⚠️
src/handlers/openai-agents/embedded-tools.ts 94.04% 5 Missing ⚠️
src/handlers/openai-agents/span-mapping.ts 96.77% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #508      +/-   ##
==========================================
+ Coverage   75.22%   76.70%   +1.47%     
==========================================
  Files          75       81       +6     
  Lines        6737     7284     +547     
  Branches     1892     2131     +239     
==========================================
+ Hits         5068     5587     +519     
- Misses       1658     1686      +28     
  Partials       11       11              
Flag Coverage Δ
unittests 76.70% <94.93%> (+1.47%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/handlers/langchain.ts 85.71% <100.00%> (ø)
src/handlers/openai-agents/custom-span.ts 100.00% <100.00%> (ø)
src/handlers/openai-agents/data-extraction.ts 100.00% <100.00%> (ø)
src/handlers/openai-agents/node.ts 100.00% <100.00%> (ø)
src/handlers/openai/usage.ts 95.65% <100.00%> (+0.53%) ⬆️
src/index.ts 100.00% <100.00%> (ø)
src/utils/galileo-logger.ts 76.91% <ø> (ø)
src/utils/serialization.ts 80.35% <100.00%> (ø)
src/wrappers.ts 92.94% <100.00%> (ø)
src/handlers/openai-agents/span-mapping.ts 96.77% <96.77%> (ø)
... and 2 more
Files with missing lines Coverage Δ
src/handlers/langchain.ts 85.71% <100.00%> (ø)
src/handlers/openai-agents/custom-span.ts 100.00% <100.00%> (ø)
src/handlers/openai-agents/data-extraction.ts 100.00% <100.00%> (ø)
src/handlers/openai-agents/node.ts 100.00% <100.00%> (ø)
src/handlers/openai/usage.ts 95.65% <100.00%> (+0.53%) ⬆️
src/index.ts 100.00% <100.00%> (ø)
src/utils/galileo-logger.ts 76.91% <ø> (ø)
src/utils/serialization.ts 80.35% <100.00%> (ø)
src/wrappers.ts 92.94% <100.00%> (ø)
src/handlers/openai-agents/span-mapping.ts 96.77% <96.77%> (ø)
... and 2 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@fernandocorreia-galileo fernandocorreia-galileo left a comment

Choose a reason for hiding this comment

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

@Murike please check if these auto-generated notes are valid.

Issues Found

  • [Major] Agent spans misclassified as workflow spans

    • File: src/handlers/openai-agents/span-mapping.ts (line 36-39) and src/handlers/openai-agents/index.ts (lines 370-379)
    • mapSpanType() maps OpenAI's 'agent' type to 'workflow', and _logNodeTree() catches all non-llm/non-tool nodes in the else branch calling addWorkflowSpan(). GalileoLogger has a distinct addAgentSpan() method (with agentType, stepNumber parameters) that should be used for agent spans to preserve the Trace→Agent hierarchy in the Galileo platform.
    • Suggestion: In mapSpanType(), map 'agent' to 'agent' instead of 'workflow'. In _logNodeTree(), add a dedicated branch for node.nodeType === 'agent' that calls this._galileoLogger.addAgentSpan(). Update the test at tracing-processor.test.ts:142 accordingly.
  • [Major] _firstInput is never populated

    • File: src/handlers/openai-agents/index.ts (lines 79, 304-305)
    • _firstInput is declared as null, reset to null in onTraceEnd, and checked in _logNodeTree — but never assigned a value anywhere. The trace-level input always falls back to the root node's input, which for agent traces is typically empty (since agent spans have input: '').
    • Suggestion: In onSpanEnd(), after extracting span data, add: if (this._firstInput === null && node.spanParams.input) { this._firstInput = node.spanParams.input; }. This captures the first non-empty input (typically from the first LLM or tool span).
  • [Major] parseUsage misses standard OpenAI token detail paths

    • File: src/handlers/openai-agents/data-extraction.ts (lines 44-53)
    • The function looks for reasoning/cached tokens under usage.details.reasoning_tokens and usage.details.cached_tokens. However, the standard OpenAI API (and Agents SDK) uses usage.output_tokens_details.reasoning_tokens and usage.input_tokens_details.cached_tokens. The current details fallback is not the correct path, so reasoning and cached token counts will be zero for all spans.
    • Suggestion: Add lookups for output_tokens_details.reasoning_tokens and input_tokens_details.cached_tokens as the primary paths, falling back to the existing details and top-level fields.
  • [Minor] GalileoCustomSpanData's galileoSpan reference is never used

    • File: src/handlers/openai-agents/index.ts (lines 158-159) and src/handlers/openai-agents/custom-span.ts
    • The createGalileoCustomSpanData() function and GalileoCustomSpanData interface provide API to embed a Galileo span reference, but onSpanStart() maps GALILEO_CUSTOM_TYPE to 'workflow' and discards the galileoSpan reference. The custom span becomes a generic workflow span with data from extractWorkflowData(). Either wire the galileoSpan into the logging path or simplify the API (remove galileoSpan if it's not needed yet).
    • Suggestion: If this is intended for future use, add a TODO comment. If it should work now, extract spanData.data.galileoSpan in onSpanStart and use it when logging the node.
  • [Minor] Orphan spans silently dropped

    • File: src/handlers/openai-agents/index.ts (lines 187-192)
    • If parentId points to a node not yet in _nodes, the new span is stored but never linked as a child. When _commitTrace walks the tree from root, orphaned spans are never visited and never logged. In normal SDK operation spans arrive in order, but out-of-order delivery (e.g., async agent flows) could cause silent data loss.
    • Suggestion: Add a fallback — if parentNode is not found, try linking to the trace root node. Add a sdkLogger.warn() when this happens.
  • [Nit] void _removed pattern for unused destructured variable

    • File: src/handlers/openai-agents/index.ts (lines 225-226)
    • const { _responseObject: _removed, ...rest } = finalData; void _removed; — the underscore-prefixed variable plus void is unusual. A cleaner pattern is just const { _responseObject: _, ...rest } = finalData; or delete the key from the object.
  • [Nit] Dynamic import warning fires eagerly at module load

    • File: src/handlers/openai-agents/index.ts (lines 25-29)
    • The top-level import('@openai/agents-core' as string).catch(...) runs as soon as the module is loaded, even if the consumer never intends to use GalileoTracingProcessor. This causes a spurious warning for users who import other Galileo features but don't use OpenAI Agents.
    • Suggestion: Move the availability check into the constructor or registerGalileoTraceProcessor() so it only fires when actually used.
  • [Nit] Trace metadata — consider defensive filtering

    • File: src/handlers/openai-agents/index.ts (lines 101-108)
    • While trace metadata is user-provided (not SDK-injected credentials), it would be a good defensive practice to at least warn or document that all metadata is forwarded verbatim to Galileo.

Questions

  • Is the GalileoCustomSpanData / galileoSpan reference intended to be functional in this PR, or is it scaffolding for a follow-up? The current API is exposed publicly but does nothing with the embedded span.
  • Should the agent type in mapSpanType map to 'agent' (using addAgentSpan()) or is the 'workflow' mapping intentional for some Galileo backend reason?
  • The _firstInput field — was there a plan to populate it that got lost during development, or is the fallback-to-root-input behavior intentional?

@Murike
Copy link
Contributor Author

Murike commented Mar 5, 2026

@Murike please check if these auto-generated notes are valid.

Issues Found

* **[Major] Agent spans misclassified as workflow spans**
  
  * File: `src/handlers/openai-agents/span-mapping.ts` (line 36-39) and `src/handlers/openai-agents/index.ts` (lines 370-379)
  * `mapSpanType()` maps OpenAI's `'agent'` type to `'workflow'`, and `_logNodeTree()` catches all non-llm/non-tool nodes in the `else` branch calling `addWorkflowSpan()`. GalileoLogger has a distinct `addAgentSpan()` method (with `agentType`, `stepNumber` parameters) that should be used for agent spans to preserve the Trace→Agent hierarchy in the Galileo platform.
  * Suggestion: In `mapSpanType()`, map `'agent'` to `'agent'` instead of `'workflow'`. In `_logNodeTree()`, add a dedicated branch for `node.nodeType === 'agent'` that calls `this._galileoLogger.addAgentSpan()`. Update the test at `tracing-processor.test.ts:142` accordingly.

* **[Major] `_firstInput` is never populated**
  
  * File: `src/handlers/openai-agents/index.ts` (lines 79, 304-305)
  * `_firstInput` is declared as `null`, reset to `null` in `onTraceEnd`, and checked in `_logNodeTree` — but never assigned a value anywhere. The trace-level input always falls back to the root node's input, which for agent traces is typically empty (since agent spans have `input: ''`).
  * Suggestion: In `onSpanEnd()`, after extracting span data, add: `if (this._firstInput === null && node.spanParams.input) { this._firstInput = node.spanParams.input; }`. This captures the first non-empty input (typically from the first LLM or tool span).

* **[Major] `parseUsage` misses standard OpenAI token detail paths**
  
  * File: `src/handlers/openai-agents/data-extraction.ts` (lines 44-53)
  * The function looks for reasoning/cached tokens under `usage.details.reasoning_tokens` and `usage.details.cached_tokens`. However, the standard OpenAI API (and Agents SDK) uses `usage.output_tokens_details.reasoning_tokens` and `usage.input_tokens_details.cached_tokens`. The current `details` fallback is not the correct path, so reasoning and cached token counts will be zero for all spans.
  * Suggestion: Add lookups for `output_tokens_details.reasoning_tokens` and `input_tokens_details.cached_tokens` as the primary paths, falling back to the existing `details` and top-level fields.

* **[Minor] GalileoCustomSpanData's `galileoSpan` reference is never used**
  
  * File: `src/handlers/openai-agents/index.ts` (lines 158-159) and `src/handlers/openai-agents/custom-span.ts`
  * The `createGalileoCustomSpanData()` function and `GalileoCustomSpanData` interface provide API to embed a Galileo span reference, but `onSpanStart()` maps `GALILEO_CUSTOM_TYPE` to `'workflow'` and discards the `galileoSpan` reference. The custom span becomes a generic workflow span with data from `extractWorkflowData()`. Either wire the `galileoSpan` into the logging path or simplify the API (remove `galileoSpan` if it's not needed yet).
  * Suggestion: If this is intended for future use, add a TODO comment. If it should work now, extract `spanData.data.galileoSpan` in `onSpanStart` and use it when logging the node.

* **[Minor] Orphan spans silently dropped**
  
  * File: `src/handlers/openai-agents/index.ts` (lines 187-192)
  * If `parentId` points to a node not yet in `_nodes`, the new span is stored but never linked as a child. When `_commitTrace` walks the tree from root, orphaned spans are never visited and never logged. In normal SDK operation spans arrive in order, but out-of-order delivery (e.g., async agent flows) could cause silent data loss.
  * Suggestion: Add a fallback — if `parentNode` is not found, try linking to the trace root node. Add a `sdkLogger.warn()` when this happens.

* **[Nit] `void _removed` pattern for unused destructured variable**
  
  * File: `src/handlers/openai-agents/index.ts` (lines 225-226)
  * `const { _responseObject: _removed, ...rest } = finalData; void _removed;` — the underscore-prefixed variable plus `void` is unusual. A cleaner pattern is just `const { _responseObject: _, ...rest } = finalData;` or delete the key from the object.

* **[Nit] Dynamic import warning fires eagerly at module load**
  
  * File: `src/handlers/openai-agents/index.ts` (lines 25-29)
  * The top-level `import('@openai/agents-core' as string).catch(...)` runs as soon as the module is loaded, even if the consumer never intends to use `GalileoTracingProcessor`. This causes a spurious warning for users who import other Galileo features but don't use OpenAI Agents.
  * Suggestion: Move the availability check into the constructor or `registerGalileoTraceProcessor()` so it only fires when actually used.

* **[Nit] Trace metadata — consider defensive filtering**
  
  * File: `src/handlers/openai-agents/index.ts` (lines 101-108)
  * While trace metadata is user-provided (not SDK-injected credentials), it would be a good defensive practice to at least warn or document that all metadata is forwarded verbatim to Galileo.

Questions

* Is the GalileoCustomSpanData / `galileoSpan` reference intended to be functional in this PR, or is it scaffolding for a follow-up? The current API is exposed publicly but does nothing with the embedded span.

* Should the `agent` type in `mapSpanType` map to `'agent'` (using `addAgentSpan()`) or is the `'workflow'` mapping intentional for some Galileo backend reason?

* The `_firstInput` field — was there a plan to populate it that got lost during development, or is the fallback-to-root-input behavior intentional?

FIXED - [Major] Agent spans misclassified as workflow spans

FIXED - [Major] _firstInput is never populated

FIXED - [Major] parseUsage misses standard OpenAI token detail paths

FIXED - [Minor] GalileoCustomSpanData's galileoSpan reference is never used

FIXED - [Minor] Orphan spans silently dropped

ANSWERED - [Nit] void _removed pattern for unused destructured variable
A: Suggestion doesn't compile (underscore still read as unused var), voiding is the less verbose solution here.

FIXED - [Nit] Dynamic import warning fires eagerly at module load

ANSWERED - [Nit] Trace metadata — consider defensive filtering
A: This is part of a bigger subject on how we are handling sensitive data on the SDK side. Won't be implemented here.

Questions

FIXED - Is the GalileoCustomSpanData / galileoSpan reference intended to be functional in this PR, or is it scaffolding for a follow-up? The current API is exposed publicly but does nothing with the embedded span.
FIXED - Should the agent type in mapSpanType map to 'agent' (using addAgentSpan()) or is the 'workflow' mapping intentional for some Galileo backend reason?
FIXED - The _firstInput field — was there a plan to populate it that got lost during development, or is the fallback-to-root-input behavior intentional?

@Murike Murike force-pushed the feature/parity-openai-agents branch from e261754 to 93f0ff4 Compare March 12, 2026 18:48
@Murike
Copy link
Contributor Author

Murike commented Mar 12, 2026

An issue with trace ingestion for an api URL different than the default is being tested, due to errors in a recent test.

@Murike Murike force-pushed the feature/parity-openai-agents branch from 93f0ff4 to f8111bc Compare March 20, 2026 00:59
@Murike Murike merged commit ca7f470 into main Mar 20, 2026
10 checks passed
@Murike Murike deleted the feature/parity-openai-agents branch March 20, 2026 19:41
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.

3 participants