diff --git a/python/packages/devui/agent_framework_devui/_executor.py b/python/packages/devui/agent_framework_devui/_executor.py index e217341511c..8d0d879ff09 100644 --- a/python/packages/devui/agent_framework_devui/_executor.py +++ b/python/packages/devui/agent_framework_devui/_executor.py @@ -375,6 +375,8 @@ async def _execute_agent( run_kwargs: dict[str, Any] = {"stream": True} if session: run_kwargs["session"] = session + if request.function_invocation_kwargs is not None: + run_kwargs["function_invocation_kwargs"] = request.function_invocation_kwargs stream = cast(Any, agent.run(user_message, **run_kwargs)) async for update in stream: diff --git a/python/packages/devui/agent_framework_devui/models/_openai_custom.py b/python/packages/devui/agent_framework_devui/models/_openai_custom.py index d64b1ec49c3..8d887a37528 100644 --- a/python/packages/devui/agent_framework_devui/models/_openai_custom.py +++ b/python/packages/devui/agent_framework_devui/models/_openai_custom.py @@ -312,6 +312,9 @@ class AgentFrameworkRequest(BaseModel): # Reasoning parameters (for o-series models) reasoning: dict[str, Any] | None = None # {"effort": "low" | "medium" | "high" | "minimal"} + # Agent Framework tool invocation context + function_invocation_kwargs: dict[str, Any] | None = None + # Optional extra_body for advanced use cases extra_body: dict[str, Any] | None = None diff --git a/python/packages/devui/tests/devui/test_execution.py b/python/packages/devui/tests/devui/test_execution.py index f1c03c1728e..9c299e41b1b 100644 --- a/python/packages/devui/tests/devui/test_execution.py +++ b/python/packages/devui/tests/devui/test_execution.py @@ -13,12 +13,16 @@ import tempfile from pathlib import Path from typing import Any +from unittest.mock import patch import pytest from agent_framework import Agent, AgentExecutor, FunctionExecutor, WorkflowBuilder # Import mock classes from conftest for direct use in some tests -from conftest import MockBaseChatClient # pyrefly: ignore[missing-import] # pyright: ignore[reportMissingImports] +from conftest import ( # pyrefly: ignore[missing-import] # pyright: ignore[reportMissingImports] + MockAgent, + MockBaseChatClient, +) from agent_framework_devui._discovery import EntityDiscovery from agent_framework_devui._executor import AgentFrameworkExecutor, EntityNotFoundError @@ -159,6 +163,27 @@ async def test_chat_client_receives_correct_messages(executor_with_real_agent): assert "2+2" in all_text, f"Expected '2+2' in messages, got text: '{all_text}'" +async def test_agent_execution_forwards_function_invocation_kwargs() -> None: + """Forward request-scoped function invocation arguments to the agent.""" + discovery = EntityDiscovery(None) + executor = AgentFrameworkExecutor(discovery, MessageMapper()) + agent = MockAgent() + entity_info = await discovery.create_entity_info_from_object(agent, source="test") + discovery.register_entity(entity_info.id, entity_info, agent) + request = AgentFrameworkRequest( + metadata={"entity_id": entity_info.id}, + input="hello", + stream=True, + function_invocation_kwargs={"tenantId": "abc123"}, + ) + + with patch.object(agent, "run", wraps=agent.run) as run_spy: + async for _ in executor.execute_streaming(request): + pass + + assert run_spy.call_args.kwargs["function_invocation_kwargs"] == {"tenantId": "abc123"} + + # ============================================================================= # Workflow Execution Tests (using real WorkflowBuilder with FunctionExecutor) # =============================================================================