Skip to content

Overhauled config implementation - #636

Merged
Rodrigo Brandão (rodrigobr-msft) merged 9 commits into
mainfrom
users/robrandao/config-overhaul
Oct 28, 2026
Merged

Rodrigo Brandão (rodrigobr-msft) merged 9 commits into
mainfrom
users/robrandao/config-overhaul

Conversation

@rodrigobr-msft

@rodrigobr-msft Rodrigo Brandão (rodrigobr-msft) commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Introduces a reusable, dictionary-backed Configuration API in microsoft_agents.activity.config, with shared lookup, conversion, binding, and logging infrastructure. The existing load_configuration_from_env() return contract is retained.

Changes

  • Add ::-separated paths, ordered alternative keys, path()/xpath() helpers, nested sections, and matched source paths in diagnostics.
  • Add typed boolean, integer, float, and string getters; nullable convenience getters; string-list and scope parsing; and wildcard collection helpers.
  • Add mapping/default resolution utilities that support nested and flattened paths, __ environment-variable separators, and indexed-mapping conversion to lists.
  • Add configuration protocols and configurable-object base classes for constructing settings from mappings or configuration sections.
  • Split logging into dedicated configuration, loading, constants, and color-formatting modules. Accept LOGLEVEL, LOG_LEVEL, and log_level aliases.
  • Preserve legacy coercion wrappers, including boolean fallback behavior, while keeping input values out of the revised conversion error messages.
  • Add configuration, binding, logging, resolution, and coercion tests, and explicitly set the pytest-asyncio fixture loop scope to function.

Compatibility and scope

  • Configuration is a dict subclass. Construction is shallow, so nested mutable values can remain shared.
  • Default resolution skips empty lists and rejects conflicting scalar/section paths.
  • The legacy environment loader still returns AGENTAPPLICATION, CONNECTIONS, and CONNECTIONSMAP; this PR does not migrate existing SDK consumers to the new API.
  • The PR also removes existing ChannelId.includes() test cases without changing the ChannelId implementation.

Validation

  • Copilot ran the four new configuration test files and the existing coercion test file against commit e26101e on Python 3.12.10: 241 passed.
  • An additional smoke check verified the legacy environment loader's empty-input return contract.
  • GitHub checks are green, including the Python 3.10-3.14 build jobs, analysis checks, and CLA check.
  • Additional local loader/channel tests could not collect because the local environment lacks the hosting package's OpenTelemetry dependency; the full repository suite was not run locally.

Description prepared by Copilot from the PR changes and observed validation results.

This comment was marked as resolved.

This comment was marked as resolved.

This comment was marked as resolved.

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.

🔵 Needs a closer look

Configuration resolution can mutate nested caller-owned settings, and logging validation rejects valid read-only mappings.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

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.

🔵 Needs a closer look

Configuration resolution mutates nested caller-owned inputs, including defaults, and logging configuration rejects valid read-only mappings.

No open issues 🎉

Review effort: Balanced

@rodrigobr-msft
Rodrigo Brandão (rodrigobr-msft) marked this pull request as draft October 28, 2026 13:47
@rodrigobr-msft
Rodrigo Brandão (rodrigobr-msft) marked this pull request as ready for review October 28, 2026 13:50

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.

Copilot reproduced both issues below against the unchanged PR head, e26101ea05294c80e4bb05be525f2e91f52f713e. The earlier review threads are resolved, but these behaviors remain reproducible.

Medium: Default resolution mutates nested caller-owned settings

Location: libraries/microsoft-agents-activity/microsoft_agents/activity/config/_utils.py:317.

The shallow list copy retains references to nested containers. During configuration construction, _convert_lists(resolved) then normalizes those shared containers in place, changing the caller's primary settings or defaults before construction returns.

from microsoft_agents.activity.config import Configuration

source = {"Entries": [{"Scopes": {"0": "read"}}]}
Configuration.from_mapping(source, Unrelated=True)

assert source["Entries"][0]["Scopes"] == {"0": "read"}

The assertion fails: source["Entries"][0]["Scopes"] has become ["read"]. Starting with a fresh source, Configuration.from_mapping({"Unrelated": True}, **source) also mutates the caller-owned defaults.

This is not only the documented sharing of nested values after shallow construction: binding itself changes the input. Copy the nested containers that normalization traverses, including containers inside lists, before converting them.

Medium: Logging validation rejects read-only mappings

Location: libraries/microsoft-agents-activity/microsoft_agents/activity/config/_logging/_logging_configuration.py:46.

Configuration binding accepts Mapping inputs and preserves nested mappings, but this validation requires a concrete dict. A read-only log-level mapping therefore raises ValueError during configuration loading, although the previous logging implementation could iterate it.

from types import MappingProxyType
from microsoft_agents.activity.config import load_configuration_from_env

load_configuration_from_env({
    "LOGGING__LOGLEVEL": MappingProxyType({"default": "DEBUG"})
})

Expected: configure the default logger at DEBUG. Actual: ValueError. The same rejection occurs through _LoggingConfiguration.from_mapping({"LOGLEVEL": ...}).

Validate against Mapping rather than dict, retaining rejection of non-mapping values.

@rodrigobr-msft
Rodrigo Brandão (rodrigobr-msft) merged commit f6afde5 into main Oct 28, 2026
10 checks passed
@rodrigobr-msft
Rodrigo Brandão (rodrigobr-msft) deleted the users/robrandao/config-overhaul branch October 28, 2026 20:58
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