Repository navigation
Python: fix(devui): read context providers from the agent's provider list - #10190
tang-ontheway wants to merge 3 commits into
Conversation
extract_agent_metadata() read the singular `context_provider` attribute, but `Agent` stores its providers in the `context_providers` list. The `hasattr` check therefore never matched, so `EntityInfo.context_provider` stayed None even when providers were configured, and the DevUI Context Provider card was never rendered. Read `context_providers` first and keep the singular attribute as a fallback for custom agent objects that still expose it.
|
tang-ontheway please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.
Contributor License AgreementContribution License AgreementThis Contribution License Agreement (“Agreement”) is agreed to by the party signing below (“You”),
|
There was a problem hiding this comment.
🟡 Changes recommended
The provider-order test uses identically named classes, so it cannot detect reversed or sorted extraction and needs distinct classes with an exact sequence assertion.
1 open issue
What changed in this PR
Fixes #8989 by reading configured context providers from the framework agent’s provider list, allowing DevUI to display them without changing the metadata response shape.
Changes:
- Extracts provider class names in configured order from
context_providers. - Retains the singular
context_providerfallback. - Adds tests for single, multiple, absent, and legacy providers.
| File | Description |
|---|---|
python/packages/devui/tests/devui/test_agent_metadata.py |
Adds regression tests for provider metadata extraction. |
python/packages/devui/agent_framework_devui/_utils.py |
Reads the provider list while preserving the singular fallback and existing metadata key. |
Review effort: Balanced
| agent = Agent( | ||
| client=Mock(model=None), | ||
| context_providers=[InMemoryHistoryProvider(), InMemoryHistoryProvider()], | ||
| ) | ||
|
|
||
| metadata = extract_agent_metadata(agent) | ||
|
|
||
| assert metadata["context_provider"] == ["InMemoryHistoryProvider", "InMemoryHistoryProvider"] |
Muhammad Abdullah Butt (1AbdullahButt)
left a comment
There was a problem hiding this comment.
Looks correct. Here's what I checked, plus two small cleanups.
- The attribute name.
Agent.__init__storesself.context_providers: list[ContextProvider] = list(context_providers or [])(core/agent_framework/_agents.py:519). There's no singularcontext_provideranywhere in core, so the oldhasattrcheck could never match a framework agent. Both discovery paths (_discovery.py:370for in-memory registration,:863for directory discovery) readagent_meta["context_provider"]intoEntityInfo.context_provider: list[str] | None(models/_discovery_models.py:49). The shape doesn't change. - The empty case. An agent with no providers keeps
None, so the frontend still hides the card. - The new tests. They build real
Agentinstances, not mocks, so they would catch a future rename of the attribute. git merge-treeagainstmainis clean.
Cleanups (optional):
hasattr(provider, "__class__")is always true. Every Python object has__class__, so the check can go, in both branches. The old code had the same no-op.for provider in providersassumes an iterable.extract_agent_metadatais called on any registered entity, including customSupportsAgentRunobjects. One that exposes a truthy, non-iterablecontext_providers(a single provider object, aMock()) would now raiseTypeErrorout of entity discovery. The old code only read attributes.if isinstance(providers, (list, tuple)):keeps it as defensive as before.
One behaviour to know about, not a bug: Agent.run appends an InMemoryHistoryProvider to self.context_providers when a session is passed and no history provider is configured (_agents.py:1604-1615). Metadata taken at discovery won't show it, but metadata re-read after a run would. That's accurate, though it may surprise someone comparing the two.
I didn't run the tests.
Reviewed with help from Claude Code.
Address the review feedback on the DevUI context provider fix: - Drop the always-true ``hasattr(provider, "__class__")`` checks. - Only iterate ``context_providers`` when it is a list or tuple, so a truthy but non-iterable value no longer raises ``TypeError`` during entity discovery. - Use two distinct provider classes in the order test and assert the exact name sequence, so reversed or sorted extraction is detected. - Cover the non-iterable ``context_providers`` case with a regression test.
|
Thanks for the review — both cleanups are in (commit
I also picked up the Copilot review comment on the order test: it now uses two distinct provider classes in non-alphabetical order ( On the Local verification: |

Motivation & Context
extract_agent_metadata()inagent_framework_devui._utilspopulated thecontext_providerfield by reading the singularcontext_providerattribute:Agentdoes not have acontext_providerattribute — it stores the configured providers in thecontext_providerslist (_agents.py:self.context_providers: list[ContextProvider] = list(context_providers or [])). Thehasattrcheck therefore never matched for any framework agent, sometadata["context_provider"]stayedNone.Both discovery paths (
_discovery.py: in-memory registration and directory discovery) read this field intoEntityInfo.context_provider, which the DevUI frontend renders as the "Context Provider" card. The result is that an agent configured with, for example,InMemoryHistoryProvider()shows no context provider at all — the card is simply absent, with no error to hint at the cause.Description & Review Guide
extract_agent_metadata()now readscontext_providersfirst and lists each configured provider's class name in the order they were configured.context_providerattribute is kept as a fallback for custom agent objects that expose only that.python/packages/devui/tests/devui/test_agent_metadata.pycovering a single configured provider, multiple providers (order preserved), an agent without providers, and the singular-attribute fallback.EntityInfo.context_provideris now populated for framework agents that configure context providers, so the DevUI Context Provider card is rendered.context_providerkey and the samelist[str] | Noneshape.None, so the frontend keeps hiding the card for them.context_providerfallback is still worth keeping, given no framework agent exposes it.Related Issue
Fixes #8989
AI Assistance
AI assistance details: An AI coding assistant helped locate the metadata extraction path, draft the regression tests, and prepare this description. The analysis, the reproduction and the test results were verified by me against
mainat commit7c2b31f.Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.