Skip to content

Python: [Bug]: Declarative agent creation mutates reusable model options #9066

Closed

Description

@ktz03

Description

AgentFactory.create_agent_from_dict() consumes chatToolMode from the caller's model.options.additionalProperties dictionary. Reusing the same definition therefore changes behavior: the first agent has tool_choice="required", while the second has the default "auto". The async factory has the same behavior. The input definition should remain unchanged, and repeated construction should preserve the configured tool choice.

I am taking on a small fix in _parse_chat_options() that copies the additional-properties mapping before extracting the option, with regressions for both factory entry points.

Code Sample

from copy import deepcopy
from unittest.mock import MagicMock
from agent_framework_declarative import AgentFactory

client = MagicMock()
client.model = "test-model"
factory = AgentFactory(client=client)
definition = {
    "kind": "Prompt",
    "name": "ReusableAgent",
    "model": {"options": {"additionalProperties": {
        "chatToolMode": "required",
        "custom_option": "kept",
    }}},
}
original = deepcopy(definition)
first = factory.create_agent_from_dict(definition)
second = factory.create_agent_from_dict(definition)
print(first.default_options["tool_choice"])   # required
print(second.default_options["tool_choice"])  # auto, expected required
assert definition == original                # fails

Error Messages / Stack Traces

No exception is raised; the second agent silently receives a different tool choice.

Package Versions

Reproduced against official main commit 2df61296bb563a95552b18491ad29b1e1a509f81: agent-framework-core 1.20.0 and agent-framework-declarative 1.2.0 source.

Python Version

Python 3.12.14 and 3.14.3 on Windows.

Additional Context

The reproduction uses the public factory entry points with an injected mock client. No model or network call is made. required, none, and auto all remove the key from the caller's definition; required and none also change on the second construction. The change is limited to configuration parsing, with no function-loop or provider transport change.

Activity

  1. added
    pythonUsage: [Issues, PRs], Target: Python
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Oct 5, 2026
  2. added
    reproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow
    on Oct 5, 2026
  3. github-actions commented on Oct 5, 2026

    @github-actions
    Contributor

    🤖 Automated triage reproduction notes (agent-authored — trust but verify)

    Agent analysis

    Repro: python/packages/declarative/agent_framework_declarative/_loader.py::AgentFactory._parse_chat_options at line 743 mutates ModelOptions.additionalProperties when chatToolMode is present; both dictionary factory entry points exhibit this when called twice with the same definition. Minimal repro: inject a MagicMock client, configure chatToolMode="required", invoke either factory twice on one dictionary, and compare both tool choices and the dictionary against a deep copy; the observed values are ['required', 'auto', False].

    • Failing test: python/packages/declarative/tests/test_declarative_loader.py
    • Files examined: python/packages/declarative/agent_framework_declarative/_loader.py, python/packages/declarative/tests/test_declarative_loader.py, python/packages/declarative/pyproject.toml, python/packages/core/pyproject.toml
    • Tests run: test_create_agent_from_dict_chat_options_in_default_options, test_create_agent_from_dict_async_with_client, test_create_agent_from_dict_preserves_reusable_model_options, test_create_agent_from_dict_async_preserves_reusable_model_options
    • Reported version: agent-framework-declarative 1.2.0
    • Current version: agent-framework-declarative 1.2.0
  4. added
    declarativeUsage: [Issues, PRs], Target: declarative agents and workflows
    and removed
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

declarativeUsage: [Issues, PRs], Target: declarative agents and workflowspythonUsage: [Issues, PRs], Target: PythonreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions