🐛 Bugfix: default OpenAIModel observer to a fresh instance, not the class - #3956
Open
XixianWasTaken wants to merge 1 commit into
Open
XixianWasTaken wants to merge 1 commit into
XixianWasTaken wants to merge 1 commit into
Conversation
…lass `OpenAIModel.__init__` declared `observer: MessageObserver = MessageObserver`, so any caller that omitted `observer` stored the class object and crashed in the streaming path with `TypeError: MessageObserver.add_model_new_token() missing 1 required positional argument: 'new_token'` after the provider request had already been billed. Default `observer` to `None` and build a `MessageObserver()` lazily in `__init__`, so each model gets its own observer instead of a shared signature-level instance. Explicit observers are stored unchanged. Add regression tests covering the default instance, per-instance isolation, explicit `None`, and the streaming call that previously raised. Fixes ModelEngine-Group#3921 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
XixianWasTaken
requested review from
Dallas98,
WMC001,
YehongPan,
hhhhsc701 and
jeffwu-1999
as code owners
September 18, 2026 15:12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #3921
OpenAIModel.__init__declaredobserver: MessageObserver = MessageObserver— the default was the class object, not an instance. Any caller that omittedobservercrashed in the streaming path with:…and only after the provider request had already succeeded (and been billed).
Changes
sdk/nexent/core/models/openai_llm.pyobservernow defaults toNone;__init__builds aMessageObserver()lazily when it is omitted, so each model gets its own observer rather than a signature-level instance shared across every model. Explicit observers are stored unchanged.test/sdk/core/models/test_openai_llm_observer_default.py(new)MessageObserverinstance, not the class.Nonebehaves like omitting it.observeromitted succeeds and the default observer captures the streamed tokens (client.chat.completions.createmocked, no network).The subclasses mentioned in the issue (
openai_vlm.py,openai_long_context_model.py) already declareobserveras a required positional parameter, so they were not affected and are unchanged.Verification
Backend venv per
AGENTS.md(Python 3.11.9,uv sync --extra data-process --extra test,uv pip install -e "../sdk[dev]"), each file run in its own pytest process astest/run_all_test.pydoes:test/sdk/core/models/test_openai_llm_observer_default.pytest/sdk/core/models/test_openai_llm.pytest/sdk/core/models/test_openai_long_context_model.pytest/sdk/core/models/test_openai_vlm.pytest/sdk/core/models/test_vlm_adapter.pytest/sdk/core/models/test_dashscope_vlm_adapter.pytest/sdk/core/agents/test_nexent_agent_context_runtime_factory.pytest/backend/agents/test_context_budget_v2_pipeline.pyWith the fix temporarily reverted, the new test file fails 4/5 with the exact
TypeErrorfrom the issue, confirming it reproduces the bug.Ruff was not run locally (not available offline in this environment); added lines are within the SDK's 119-character limit and both files compile.
🤖 Generated with Claude Code