Skip to content

Python: Honor replace usage snapshots in Foundry hosting - #10205

Open
Mehedi Hasan (Mahdi-Hasan) wants to merge 3 commits into
microsoft:mainfrom
Mahdi-Hasan:fix/10189-hosting-usage-replace
Open

Mehedi Hasan (Mahdi-Hasan) wants to merge 3 commits into
microsoft:mainfrom
Mahdi-Hasan:fix/10189-hosting-usage-replace

Conversation

@Mahdi-Hasan

@Mahdi-Hasan Mehedi Hasan (Mahdi-Hasan) commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Motivation & Context

Foundry hosting reports the wrong token usage when an agent streams cumulative usage snapshots. _OutputItemTracker added every usage update, even ones with merge_mode="replace". Two snapshots of 100/10 and 250/25 were reported as 350/35 instead of 250/25.

Description & Review Guide

  • What are the major changes?
    • In _OutputItemTracker.handle, a replace usage update now replaces the tracked usage. append updates are still added.
    • This is the same rule as Content._add_usage_content and AgentResponse.from_updates.
  • What is the impact of these changes?
    • Only the usage in the final response.completed event changes, and only when the agent sends replace updates.
    • Agents that send only append updates get the same totals as before.
  • What do you want reviewers to focus on?
    • The replaced value is a deepcopy, so the tracker never holds a reference to the update's usage_details.

Related Issue

Fixes #10189

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: implementation, tests, and this description.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

🤖 Generated with Claude Code

_OutputItemTracker added every usage update with add_usage_details, even
when the update had merge_mode="replace". Two cumulative snapshots of
100/10 and 250/25 were reported as 350/35. Replace the tracked usage for
replace updates and keep adding append updates, the same rule as
Content._add_usage_content and AgentResponse.from_updates.

Fixes microsoft#10189

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

A moderate active finding remains because the added test does not verify that replacement usage details are copied rather than retained by reference.

1 open issue

Review effort: Lite

Mehedi Hasan (Mahdi-Hasan) added a commit to Mahdi-Hasan/Mahdi-Hasan that referenced this pull request Nov 9, 2026
* Add agent-framework #10205; bump OSS count to 61 PRs

- Foundry hosting fix for replace usage snapshots (microsoft/agent-framework#10205)
- Projects stay at 19: agent-framework is already listed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add Nov 9 PRs; bump OSS counts to 70 PRs / 21 projects

- quran.com-frontend-next #3368-#3370
- New projects: quranic-universal-library #1021-#1023, hadith-api #144-#146

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The merge-mode test only checked totals, so it would still pass if the
tracker kept the update's usage_details by reference. Mutate the update
after handle() and check the tracker's usage is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
self._usage_details = add_usage_details(self._usage_details, content.usage_details)
# A "replace" update is a cumulative snapshot, so it supersedes earlier usage instead of adding to it.
if content.merge_mode == "replace":
self._usage_details = deepcopy(content.usage_details)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Mehedi Hasan (@Mahdi-Hasan), this replaces the tracker-wide usage slot, so a later executor's snapshot erases usage already accumulated from earlier agents in a hosted workflow. For example, agent A reporting 1000/100 followed by agent B reporting 50/5 produces 50/5 instead of 1050/105. Can we scope replacement to the same logical agent/response stream and add a multi-executor regression?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in d68981f. The tracker now keeps usage per (author_name, response_id) stream. A replace snapshot overwrites only its own stream, and the reported usage is the sum over all streams. A re-run of the same agent gets a new response_id, so both runs count.

Added TestWorkflowAgentHosting::test_replace_usage_from_each_executor_is_summed: two chained agents report 1000/100 and 50/5, and the response reports 1050/105. Before the fix it reported 50/5. There is also a tracker-level test, test_output_item_tracker_scopes_replace_usage_to_its_stream.

A hosted workflow sends every executor's updates through one
_OutputItemTracker. A replace snapshot from a later agent erased usage
already tracked for earlier agents: 1000/100 then 50/5 gave 50/5
instead of 1050/105.

Track usage per (author_name, response_id) stream. A replace update
overwrites only its own stream and the reported usage is the sum over
all streams. Add a tracker test and a two-executor workflow regression.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was previously deployed

1 inactive deployment
github-app-auth — d68981f8 Deployed Nov 10, 2026 by Mahdi-Hasan via add_label #27470
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Foundry hosting sums replacement usage snapshots, inflating reported tokens

3 participants