Skip to content

feat(usage): add agent_name and model_name to RequestUsage (#2100)#4

Open
adityasingh2400 wants to merge 151 commits into
mainfrom
feat/request-usage-agent-model-identifiers-2100-clean
Open

feat(usage): add agent_name and model_name to RequestUsage (#2100)#4
adityasingh2400 wants to merge 151 commits into
mainfrom
feat/request-usage-agent-model-identifiers-2100-clean

Conversation

@adityasingh2400
Copy link
Copy Markdown
Owner

@adityasingh2400 adityasingh2400 commented Apr 14, 2026

Summary

Adds optional agent_name and model_name fields to RequestUsage so developers can attribute token usage and costs to specific agents and models in multi-agent workflows.

Problem

In complex multi-agent systems, result.context_wrapper.usage.request_usage_entries contains one RequestUsage per LLM call, but there is no way to know which agent or model generated each entry. This makes per-agent cost attribution impossible.

Solution

  • Added agent_name: str | None = None and model_name: str | None = None to RequestUsage (backward-compatible — defaults to None)
  • Modified Usage.add() to accept keyword-only agent_name and model_name parameters and annotate the resulting RequestUsage entry
  • Added _get_model_name() helper that safely duck-types the model name from any Model implementation (e.g. OpenAIResponsesModel.model, OpenAIChatCompletionsModel.model)
  • Updated both run_single_turn_streamed and get_new_response call-sites in run_loop.py to pass agent.name and resolved model name
  • When merging pre-existing request_usage_entries, agent/model names are applied only to entries that don't already have them (existing names preserved)
  • Updated serialize_usage / deserialize_usage to round-trip the new fields through JSON
  • Zero breaking changes — existing code constructing RequestUsage or calling Usage.add() without these fields continues to work

Before / After

# Before
RequestUsage(input_tokens=65, output_tokens=13, ...)

# After
RequestUsage(agent_name="Math Tutor", model_name="gpt-4o", input_tokens=65, output_tokens=13, ...)

Usage Example

result = await Runner.run(triage_agent, input="help me")

for entry in result.context_wrapper.usage.request_usage_entries:
    print(f"{entry.agent_name} ({entry.model_name}): {entry.input_tokens} in / {entry.output_tokens} out")
# Triage Agent (gpt-4o-mini): 100 in / 10 out
# Specialist Agent (gpt-4o): 200 in / 20 out

Files Changed

File Change
src/agents/usage.py Added agent_name/model_name fields to RequestUsage; updated Usage.add(), serialize_usage, deserialize_usage
src/agents/run_internal/run_loop.py Added _get_model_name() helper; updated both usage.add() call-sites
tests/test_usage.py Added 9 new tests

Test Plan

  • Unit tests for RequestUsage field population (explicit + default None)
  • Usage.add() propagation and backward compat tests
  • Entry merge semantics (names applied to un-named entries; existing names preserved)
  • Single-agent runner integration test confirming agent_name is set
  • Model-name detection test via duck-typed .model attribute
  • Multi-agent scenario: each RequestUsage entry has the correct agent_name
  • Full suite: 2198 tests pass, lint clean, pyright clean

Closes openai#2100

Summary by CodeRabbit

  • New Features

    • Usage tracking now records agent and model names with each request for better attribution; model name is included only when reliably available. Merging preserves existing attribution and avoids mutating original usage entries.
  • Tests

    • Added tests verifying capture, preservation, merging, immutability, and correct attribution across single- and multi-agent runs.

elainegan-openai and others added 30 commits March 19, 2026 14:30
**Default guidance in public documentation**
https://openai.github.io/openai-agents-python/

**Before**
The public Agents SDK docs still mostly pointed realtime users at
gpt-realtime, so new users were landing on stale guidance instead of the
recommended gpt-realtime-1.5 path. This showed up in the top-level docs
entry points and the English realtime quickstart/guide.

**After**
The public documentation now points new realtime users to
gpt-realtime-1.5 in the top-level discovery pages and the English
realtime quickstart/guide. The SDK’s implicit runtime default was
intentionally left unchanged, so this updates guidance without changing
behavior for existing integrations that omit model_name.
Co-authored-by: Kazuhiro Sera <seratch@openai.com>
Co-authored-by: Kazuhiro Sera <seratch@openai.com>
seratch and others added 7 commits April 21, 2026 11:50
This pull request improves sandbox backend persistence by extracting the
common ephemeral mount teardown and restore flow into a shared session
helper. Cloudflare and Vercel persistence now use the shared lifecycle
wrapper for persist and hydrate operations while preserving existing
archive error precedence and corruption context metadata.
This pull request improves sandbox workspace persistence internals by
sharing the shell `tar --exclude` argument generation used by Blaxel,
Daytona, and E2B sandbox sessions.

It adds a small common helper under `src/agents/sandbox/session/` and
keeps each provider's existing private `_tar_exclude_args()` surface as
a thin delegate, preserving the generated command strings while removing
duplicated quoting, sorting, and path-normalization logic. Direct unit
coverage was added for empty/dot paths, stable sorting, shell quoting,
dot-prefixed patterns, and absolute-path normalization.
This pull request improves the sandbox session implementation by moving
archive extraction, manifest application, and snapshot lifecycle logic
out of `BaseSandboxSession` into focused helper modules. The existing
`BaseSandboxSession` method surface remains in place and delegates to
the new helpers, preserving provider overrides and compatibility while
reducing the size and responsibility concentration of the base session
class.
Automated update of translated documentation.

Triggered by commit:
[4c5112c](openai@4c5112c).
Message: `feat: add BoxMount support (openai#2988)

### Summary

This pull request adds Box as an rclone-backed sandbox mount provider.

- Adds `BoxMount` with Docker rclone volume-driver support and
in-container `RcloneMountPattern` config generation.
- Wires Box into the sandbox entry exports and provider docs.
- Updates rclone-backed sandbox extension wording for Daytona, E2B, and
Runloop.
- Adds Docker and rclone mount config tests for Box auth/path options.

### Test plan

- `bash .agents/skills/code-change-verification/scripts/run.sh` *(format
and lint passed; typecheck failed on pre-existing local ignored
`tests/local` symlink files and unrelated Temporal example dependency
typing)*
- `uv run pyright --project pyrightconfig.json src/agents/sandbox
src/agents/extensions/sandbox tests/sandbox/test_mounts.py
tests/sandbox/test_docker.py`
- `uv run mypy src/agents/sandbox src/agents/extensions/sandbox
tests/sandbox/test_mounts.py tests/sandbox/test_docker.py`
- `uv run pytest -q tests/sandbox/test_mounts.py
tests/sandbox/test_docker.py`

### Issue number

N/A

### Checks

- [x] I've added new tests (if relevant)
- [x] I've added/updated the relevant documentation
- [x] I've run `make lint` and `make format`
- [x] I've made sure tests pass

Co-authored-by: Carter Rabasa <carter.rabasa@gmail.com>`

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
### Release readiness review (v0.14.3 -> TARGET
ba3b177)

This is a release readiness report done by `$final-release-review`
skill.

### Diff


openai/openai-agents-python@v0.14.3...ba3b177

### Release call:
**🟢 GREEN LIGHT TO SHIP** Patch bump to `0.14.4` with additive sandbox
capability and broad compatibility-focused test coverage; no concrete
release-blocking issues found in the diff.

### Scope summary:
- 34 files changed (+2236/-536); key areas touched:
`src/agents/sandbox/session/` refactors/extractions, new `BoxMount`
support in sandbox mount providers, provider integrations (`cloudflare`,
`vercel`, `daytona`, `e2b`, `blaxel`), sandbox docs, and substantial
sandbox compatibility/regression tests.
- Commit range reviewed (oldest to newest): docs cleanup/translation
updates, sandbox compatibility guards, snapshot default fix, Box mount
feature, shared mount lifecycle refactor, shared tar exclude refactor,
session helper extraction, version bump to `0.14.4`.

### Risk assessment (ordered by impact):
No material risks identified.

### Notes:
- Base tag determined from local tags only per instruction: `v0.14.3`.
- Target resolved from current `HEAD`:
`ba3b17740b280c00330d9cd61158f88a34d28d2a`.
- Assessment is based on diff/log/code inspection and added tests
in-range; no additional local test execution was performed in this CI
review step.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
adityasingh2400 added a commit that referenced this pull request Apr 22, 2026
…, defensive _get_model_name

Three small follow-ups from the CodeRabbit review of PR #4:

  * test_multi_agent_run_attributes_usage_to_correct_agents now sets a
    distinct model attribute on each FakeModel and asserts model_name on
    both the triage and specialist RequestUsage entries, so a regression
    that drops or cross-wires model_name during handoff aggregation will
    surface here too.
  * Adds test_serialize_deserialize_roundtrip_preserves_agent_and_model_names
    that builds a Usage with both a named and an unnamed RequestUsage entry,
    runs serialize_usage then deserialize_usage, and asserts both fields
    survive on the named entry while staying None on the unnamed one. This
    exercises both branches of the conditional emit in serialize_usage.
  * Hardens _get_model_name against custom Model implementations whose
    descriptors or properties raise on attribute access: the helper now
    swallows exceptions, falls back to model_name when model is missing,
    and rejects empty strings. This keeps usage accounting from ever
    crashing the run on a third-party Model.
ankitphogat and others added 18 commits April 23, 2026 09:32
…tool items (openai#3027)

Co-authored-by: Daniel Cufiño <dancufino@gmail.com>
- Added optional `agent_name: str | None = None` and `model_name: str | None = None`
  fields to the `RequestUsage` dataclass (backward-compatible)
- Modified `Usage.add()` to accept keyword-only `agent_name` and `model_name`
  parameters and annotate the resulting `RequestUsage` entry with them
- Added `_get_model_name()` helper in run_loop.py to safely extract the model
  name string from any Model implementation via duck-typing
- Updated both `run_single_turn_streamed` and `get_new_response` call-sites in
  run_loop.py to pass agent.name and the resolved model name when adding usage
- When merging pre-existing `request_usage_entries`, agent/model names are
  applied to entries that don't already have them set (existing names preserved)
- Updated `serialize_usage` / `deserialize_usage` in usage.py to round-trip
  the new fields through JSON
- Added 9 new tests covering: default None values (backward compat),
  explicit field population, Usage.add() propagation, entry merge semantics,
  single-agent runner integration, model_name detection, and multi-agent
  per-agent attribution scenario
- Full test suite passes (2198 tests); lint and pyright clean

Closes openai#2100
The elif branch in Usage.add() was mutating agent_name/model_name directly
on the RequestUsage objects inside other.request_usage_entries, bypassing
the non-overwrite guard and causing silent mis-attribution when the same
Usage instance was added to multiple aggregators.

Fix: create a new RequestUsage copy for each entry with the annotation
applied, leaving the originals unchanged.

Adds a regression test that verifies the original entries are not mutated.
…, defensive _get_model_name

Three small follow-ups from the CodeRabbit review of PR #4:

  * test_multi_agent_run_attributes_usage_to_correct_agents now sets a
    distinct model attribute on each FakeModel and asserts model_name on
    both the triage and specialist RequestUsage entries, so a regression
    that drops or cross-wires model_name during handoff aggregation will
    surface here too.
  * Adds test_serialize_deserialize_roundtrip_preserves_agent_and_model_names
    that builds a Usage with both a named and an unnamed RequestUsage entry,
    runs serialize_usage then deserialize_usage, and asserts both fields
    survive on the named entry while staying None on the unnamed one. This
    exercises both branches of the conditional emit in serialize_usage.
  * Hardens _get_model_name against custom Model implementations whose
    descriptors or properties raise on attribute access: the helper now
    swallows exceptions, falls back to model_name when model is missing,
    and rejects empty strings. This keeps usage accounting from ever
    crashing the run on a third-party Model.
@adityasingh2400 adityasingh2400 force-pushed the feat/request-usage-agent-model-identifiers-2100-clean branch from 5ac2475 to fa0a85f Compare April 26, 2026 21:07
…add()

When other.requests == 1 but other.request_usage_entries is already populated,
merge those entries (with the same agent_name/model_name annotation rules as
the multi-entry path) instead of creating a fresh RequestUsage that only used
add() kwargs and dropped prior attribution.

Adds regression test for Codex review on PR openai#2914.
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.

Track Agent and Model Identifiers in Usage Statistics