From c0d6ed66afe05b61c678e4775392245ea4532901 Mon Sep 17 00:00:00 2001 From: ktz03 <2484593937@qq.com> Date: Tue, 6 Oct 2026 00:59:39 +0800 Subject: [PATCH] Python: preserve reusable declarative model options --- .../agent_framework_declarative/_loader.py | 7 ++-- .../tests/test_declarative_loader.py | 33 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/python/packages/declarative/agent_framework_declarative/_loader.py b/python/packages/declarative/agent_framework_declarative/_loader.py index 5e7e0b8cf27..a58c993c084 100644 --- a/python/packages/declarative/agent_framework_declarative/_loader.py +++ b/python/packages/declarative/agent_framework_declarative/_loader.py @@ -740,10 +740,11 @@ def _parse_chat_options(self, model: Model | None) -> dict[str, Any]: chat_options["stop"] = options.stopSequences if options.allowMultipleToolCalls is not None: chat_options["allow_multiple_tool_calls"] = options.allowMultipleToolCalls - if (chat_tool_mode := options.additionalProperties.pop("chatToolMode", None)) is not None: + additional_properties = options.additionalProperties.copy() + if (chat_tool_mode := additional_properties.pop("chatToolMode", None)) is not None: chat_options["tool_choice"] = chat_tool_mode - if options.additionalProperties: - chat_options["additional_chat_options"] = options.additionalProperties + if additional_properties: + chat_options["additional_chat_options"] = additional_properties return chat_options def _parse_tools(self, tools: list[Tool] | None) -> list[AFFunctionTool | dict[str, Any]] | None: diff --git a/python/packages/declarative/tests/test_declarative_loader.py b/python/packages/declarative/tests/test_declarative_loader.py index bde08e69390..c3066178869 100644 --- a/python/packages/declarative/tests/test_declarative_loader.py +++ b/python/packages/declarative/tests/test_declarative_loader.py @@ -3,6 +3,7 @@ import builtins import sys import threading +from copy import deepcopy from pathlib import Path from typing import Any from unittest.mock import AsyncMock, MagicMock, patch @@ -643,6 +644,38 @@ def test_create_agent_from_dict_chat_options_in_default_options(self): assert agent.default_options.get("temperature") == 0.7 assert agent.default_options.get("top_p") == 0.9 + @pytest.mark.parametrize("use_async", [False, True]) + @pytest.mark.parametrize("tool_choice", ["auto", "required", "none", None]) + async def test_create_agent_from_dict_preserves_reused_model_options( + self, tool_choice: str | None, use_async: bool + ) -> None: + """Reusing a definition preserves caller options and each agent's tool choice.""" + from agent_framework_declarative import AgentFactory + + additional_properties: dict[str, Any] = {"custom_option": {"nested": ["value"]}} + if tool_choice is not None: + additional_properties["chatToolMode"] = tool_choice + agent_def: dict[str, Any] = { + "kind": "Prompt", + "name": "ReusableAgent", + "model": {"options": {"additionalProperties": additional_properties}}, + } + original = deepcopy(agent_def) + mock_client = MagicMock() + mock_client.model = "test-model" + factory = AgentFactory(client=mock_client) + + for _ in range(2): + if use_async: + agent = await factory.create_agent_from_dict_async(agent_def) + else: + agent = factory.create_agent_from_dict(agent_def) + + assert agent.default_options["tool_choice"] == (tool_choice or "auto") + assert agent.default_options["additional_chat_options"] == {"custom_option": {"nested": ["value"]}} + + assert agent_def == original + class TestAgentFactorySafeMode: """Tests for AgentFactory safe_mode parameter."""