Commit Graph

787 Commits

  • Python: Add header_provider to Streamable HTTP MCP servers (#4849)
    * Python: Add header_provider to MCPStreamableHTTPTool (#4808)
    
    Add a header_provider callback parameter to MCPStreamableHTTPTool that
    enables injecting dynamic per-request HTTP headers from runtime kwargs
    (originating from FunctionInvocationContext.kwargs set in agent middleware).
    
    The implementation uses contextvars and httpx event hooks to ensure headers
    are task-local and safe for concurrent tool calls:
    
    - header_provider receives the runtime kwargs dict and returns headers
    - call_tool sets a ContextVar before delegating to MCPTool.call_tool
    - An httpx request event hook reads from the ContextVar and injects headers
    
    Example usage:
        mcp_tool = MCPStreamableHTTPTool(
            name="web-api",
            url="https://api.example.com/mcp",
            header_provider=lambda kwargs: {
                "X-Auth-Token": kwargs.get("auth_token", ""),
            },
        )
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4808: Python: [Bug]: Unable to pass AgentContext to MCPStreamableHTTPTool
    
    * Add test for header_provider via FunctionTool.invoke with FunctionInvocationContext
    
    Addresses PR review comment: exercises the full pipeline from
    FunctionInvocationContext.kwargs through FunctionTool.invoke to
    MCPStreamableHTTPTool.call_tool and header_provider, rather than
    testing call_tool in isolation.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4808: review comment fixes
    
    * Fix streamable MCP transport defaults
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix Azure AI test client mocks
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix MCP runtime kwarg regressions
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Stabilize MCP tool runtime kwargs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Use context kwargs in MCP wrappers
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated mcp samples
    
    * fix link
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Foundry Evals integration for Python (#4750)
    * Foundry Evals integration for Python
    
    Merged and refactored eval module per Eduard's PR review:
    
    - Merge _eval.py + _local_eval.py into single _evaluation.py
    - Convert EvalItem from dataclass to regular class
    - Rename to_dict() to to_eval_data()
    - Convert _AgentEvalData to TypedDict
    - Simplify check system: unified async pattern with isawaitable
    - Parallelize checks and evaluators with asyncio.gather
    - Add all/any mode to tool_called_check
    - Fix bool(passed) truthy bug in _coerce_result
    - Remove deprecated function_evaluator/async_function_evaluator aliases
    - Remove _MinimalAgent, tighten evaluate_agent signature
    - Set self.name in __init__ (LocalEvaluator, FoundryEvals)
    - Limit FoundryEvals to AsyncOpenAI only
    - Type project_client as AIProjectClient
    - Remove NotImplementedError continuous eval code
    - Add evaluation samples in 02-agents/ and 03-workflows/
    - Update all imports and tests (167 passing)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: resolve mypy redundant-cast errors while keeping pyright happy
    
    Use cast(list[Any], x) with type: ignore[redundant-cast] comments to
    satisfy both mypy (which considers casting Any redundant) and pyright
    strict mode (which needs explicit casts to narrow Unknown types).
    
    Also fix evaluator decorator check_name type annotation to be
    explicitly str, resolving mypy str|Any|None mismatch.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: CI failures — pyupgrade, evaluator overloads, sample API, reset attr
    
    - Apply pyupgrade: Sequence from collections.abc, remove forward-ref quotes
    - Add @overload signatures to evaluator() for proper @evaluator usage
    - Fix evaluate_workflow sample to use WorkflowBuilder(start_executor=) API
    - Fix _workflow.py executor.reset() to use getattr pattern for pyright
    - Remove unused EvalResults forward-ref string in default_factory lambda
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: skip gRPC-dependent observability test
    
    The test_configure_otel_providers_with_env_file_and_vs_code_port test
    triggers gRPC OTLP exporter creation, but the grpc dependency is
    optional and not installed by default. Add skipif decorator matching
    the pattern used by all other gRPC exporter tests in the same file.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: add nosec B101 for bandit assert check
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * style: align eval samples with repo conventions
    
    - Move module docstrings before imports (after copyright header)
    - Add -> None return type to all main() and helper functions
    - Fix line-too-long in multiturn sample conversation data
    - Add Workflow import for typed return in all_patterns_sample
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback: async fixes, sample bugs, deprecation warnings
    
    - Simplify _ensure_async_result to direct await (async-only clients)
    - Replace get_event_loop() with get_running_loop()
    - Narrow _fetch_output_items exception handling to specific types
    - Add warning log when _filter_tool_evaluators falls back to defaults
    - Add DeprecationWarning to options alias in Agent.__init__
    - Add DeprecationWarning to evaluate_response()
    - Rename raw key to _raw_arguments in convert_message fallback
    - Fix evaluate_agent_sample.py: replace evals.select() with FoundryEvals()
    - Fix evaluate_multiturn_sample.py: use Message/Content/FunctionTool types
    - Fix evaluate_workflow_sample.py: replace evals.select() with FoundryEvals()
    - Update test mocks to use AsyncMock for awaited API calls
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add test coverage for review feedback items
    
    - Add num_repetitions=2 positive test verifying 2×items and 4 agent calls
    - Add _poll_eval_run tests: timeout, failed, and canceled paths
    - Add evaluate_traces tests: validation error, response_ids path, trace_ids path
    - Add evaluate_foundry_target happy-path test with target/query verification
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix ruff ISC004 lint error and apply formatter
    
    - Wrap implicit string concatenation in parens in evaluate_multiturn_sample.py
    - Apply ruff formatter to 6 other files with minor formatting drift
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove core type changes (extracted to fix/workflow-stale-session branch)
    
    Reverts changes to _agents.py, _agent_executor.py, and _workflow.py
    back to upstream/main. These fixes are now in a separate PR.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review round 2: bugs, tests, and architecture
    
    Code fixes:
    - Fix _normalize_queries inverted condition (single query now replicates
      to match expected_count)
    - Fix substring match bug: 'end' in 'backend' matched; use exact set
      lookup for executor ID filtering
    - Fix used_available_tools sample: tool_definitions→tools param, use
      FunctionTool attribute access instead of dict .get()
    - Add None-check in _resolve_openai_client for misconfigured project
    - Add Returns section to evaluate_workflow docstring
    - Cache inspect.signature in @evaluator wrapper (avoid per-item reflection)
    
    Architecture:
    - Extract _evaluate_via_responses as module-level helper; evaluate_traces
      now calls it directly instead of creating a FoundryEvals instance
    - Move Foundry-specific typed-content conversion out of core to_eval_data;
      core now returns plain role/content dicts, FoundryEvals applies
      AgentEvalConverter in _evaluate_via_dataset
    
    Tests:
    - evaluate_response() deprecation warning emission and delegation
    - num_repetitions > 1 with expected_output and expected_tool_calls
    - Mock output_items.list in test_evaluate_calls_evals_api
    - Update to_eval_data assertions for plain-dict format
    - Unknown param error now raised at @evaluator decoration time
    
    Skipped (separate PR): executor reset loop, xfail removal, options alias
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CI: revert test_full_conversation, fix pyright errors
    
    - Revert test_full_conversation.py to upstream/main (the session
      preservation test was incorrectly changed to assert clearing)
    - Fix pyright reportUnnecessaryComparison on get_openai_client() None
      check by adding ignore comment
    - Fix pyright reportPrivateUsage: add public EvalItem.split_messages()
      method and use it in FoundryEvals._evaluate_via_dataset instead of
      accessing private _split_conversation
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review round 3: reliability, test gaps, cleanup
    
    - Add try/except guard for non-numeric score in _coerce_result
    - Add poll_interval minimum bound (0.1s) to prevent tight loops
    - Add runtime async client check in _resolve_openai_client
    - Remove _ensure_async_result wrapper (10 call sites → direct await)
    - Better error message when queries provided without agent
    - Import-time asserts for evaluator set consistency
    - Remove 28 redundant @pytest.mark.asyncio decorators
    - Add doc note about _raw_arguments sensitive data
    - Tests: tool_called_check mode=any, _normalize_queries branches,
      _extract_result_counts paths, _extract_per_evaluator, bare check
      via evaluate_agent, output_items assertion, modulo wrapping,
      async client check, queries-without-agent error
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CI: ruff S101 assert, pyright and mypy arg-type errors
    
    - Replace module-level assert with if/raise for evaluator set
      consistency checks (ruff S101 disallows bare assert)
    - Add type: ignore[arg-type] and pyright: ignore[reportArgumentType]
      on OpenAI SDK evals API calls that pass dicts where typed params
      are expected (SDK accepts dicts at runtime)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review round 4: bugs, reliability, test fixes
    
    - Fix all_passed ignoring parent result_counts when sub_results present
    - Fix _extract_tool_calls: parse string arguments via json.loads before
      falling back to None (real LLM responses use string arguments)
    - Sanitize _raw_arguments to '[unparseable]' to avoid leaking sensitive
      tool-call data to external evaluation services
    - Add NOTE comment on to_eval_data message serialization dropping
      non-text content (tool calls, results)
    - Eliminate double conversation split in _evaluate_via_dataset: build
      JSONL dicts directly from split_messages + AgentEvalConverter
    - Raise poll_interval floor from 0.1s to 1.0s to prevent rate-limit
      exhaustion
    - Fix MagicMock(name=...) bug in test: sets display name not .name attr
    - Fix mock_output_item.sample: use MagicMock object instead of dict so
      _fetch_output_items exercises error/usage/input/output extraction
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review round 5: reliability, docs, test coverage
    
    Code fixes:
    - Move import-time RuntimeError checks to unit tests (avoids breaking
      imports for all users on developer set-drift mistake)
    - _filter_tool_evaluators now raises ValueError when all evaluators
      require tools but no items have tools (was silently substituting)
    - Add poll_interval upper bound (60s) to prevent single-iteration sleep
    - Log exc_info=True in _fetch_output_items for debugging API changes
    - Fix evaluate() docstring: remove claim about Responses API optimization
    - Validate target dict has 'type' key in evaluate_foundry_target
    - Document to_eval_data() limitation: non-text content is omitted
    
    Tests:
    - TestEvaluatorSetConsistency: verify _AGENT/_TOOL subsets of _BUILTIN
    - TestEvaluateTracesAgentId: agent_id-only path with lookback_hours
    - TestFilterToolEvaluatorsRaises: ValueError on all-tool no-items
    - TestEvaluateFoundryTargetValidation: target without 'type' key
    - Assert items==[] on failed/canceled poll results
    - Mock output_items.list in response_ids test for full flow
    - TestAllPassedSubResults: result_counts=None + sub_results delegation
      and parent failures override sub_results
    - TestBuildOverallItemEmpty: empty workflow outputs returns None
    
    Skipped r5-07 (_raw_arguments length hint): marginal debugging value,
    could leak content size information.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix error message: evaluate_responses() → evaluate_traces(response_ids=...)
    
    The referenced function doesn't exist; the correct API is
    evaluate_traces(response_ids=...) from the azure-ai package.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove dead to_eval_data() method, fix docstring claims
    
    - Remove to_eval_data() from EvalItem (dead code after r4-05 JSONL refactor)
    - Migrate 15 tests from to_eval_data() to split_messages()
    - Update sample to use split_messages() + Message properties
    - Remove unimplemented Responses API optimization docstring claim
    - Update split_messages() docstring to not reference removed method
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Reduce default eval timeout from 600s to 180s (3 minutes)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove dead _evaluate_via_responses method from FoundryEvals
    
    The method was never called — evaluate() uses _evaluate_via_dataset,
    and evaluate_traces() calls _evaluate_via_responses_impl directly.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Revert unrelated formatting changes to get-started samples
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pyright: remove phantom FoundryMemoryProvider import, apply ruff format
    
    - Remove import of non-existent _foundry_memory_provider module
      (incorrectly kept during rebase conflict resolution)
    - Apply ruff formatter to test_local_eval.py and get-started samples
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix eval samples: use FoundryChatClient for Agent()
    
    The upstream provider-leading client refactor (#4818) made client=
    a required parameter on Agent(). Update the three getting-started
    eval samples to use FoundryChatClient with FOUNDRY_PROJECT_ENDPOINT,
    matching the standard pattern from 01-get-started samples.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Simplify self-reflection sample using FoundryEvals
    
    Replace ~80 lines of manual OpenAI evals API code (create_eval,
    run_eval, manual polling, raw JSONL params) with FoundryEvals:
    
    - evaluate_groundedness() uses FoundryEvals.evaluate() with EvalItem
    - Remove create_openai_client(), create_eval(), run_eval() functions
    - Remove openai SDK type imports (DataSourceConfigCustom, etc.)
    - run_self_reflection_batch creates FoundryEvals instance once,
      reuses it for all iterations across all prompts
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Update eval samples to FoundryChatClient and FOUNDRY_PROJECT_ENDPOINT
    
    - Migrate all foundry_evals samples from AzureOpenAIResponsesClient to FoundryChatClient
    - Update env var from AZURE_AI_PROJECT_ENDPOINT to FOUNDRY_PROJECT_ENDPOINT
    - Use AzureCliCredential consistently across all samples
    - Fix README.md: correct function names (evaluate_dataset -> FoundryEvals.evaluate, evaluate_responses -> evaluate_traces)
    - Update self_reflection .env.example and README.md
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix lint errors in eval samples (E501, ASYNC240, formatting)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove evaluate_all_patterns_sample.py (redundant with focused samples)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix async credential mismatch: use azure.identity.aio for async AIProjectClient
    
    AIProjectClient from azure.ai.projects.aio requires an async credential.
    Switch all foundry_evals samples from azure.identity.AzureCliCredential
    to azure.identity.aio.AzureCliCredential. Also pass project_client to
    FoundryChatClient instead of duplicating endpoint+credential.
    
    Close credential in self_reflection sample to avoid resource leak.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Revert test_observability.py to upstream/main (not our test)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address moonbox3 review: sphinx docstrings, pagination, isinstance check
    
    - Convert all Example:: / Typical usage:: code blocks to .. code-block:: python
      format matching codebase convention (both _evaluation.py and _foundry_evals.py)
    - Add async pagination in _fetch_output_items via async for (handles large result sets)
    - Replace hasattr(__aenter__) with isinstance(client, AsyncOpenAI) in _resolve_openai_client
    - Move AsyncOpenAI import from TYPE_CHECKING to runtime (needed for isinstance)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix test failures and address remaining moonbox3 review comments
    
    - Fix tests: use MagicMock(spec=AsyncOpenAI) for project_client mocks
      (isinstance check now requires proper type, not duck-typing)
    - Fix tests: replace mock_page.__iter__ with _AsyncPage helper for async for
    - Fix evaluate_response: auto-extract queries from response messages when
      query is not provided (previously always raised ValueError)
    - Add debug logging when skipping internal _-prefixed executor IDs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address Tao's PR review comments on Foundry Evals
    
    - T1: Add comment explaining builtin.* pass-through in _resolve_evaluator
    - T2: Add comment referencing OpenAI evals API for testing_criteria dict
    - T3: Document Mustache-style {{item.*}} template placeholders
    - T4: Document poll loop 60s sleep upper bound rationale
    - T5: Narrow run type to RunRetrieveResponse, use typed field access
      instead of vars()/getattr dance in _extract_result_counts and
      _extract_per_evaluator; use run.error and run.report_url directly
    - T6: Clarify openai_client docstring re: Azure Foundry endpoint
    - T8: Remove misleading empty expected_tool_calls from sample
    - Update tests to match real SDK PerTestingCriteriaResult shape
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove unnecessary Any union from run type annotations
    
    RunRetrieveResponse is the correct type — no backward compat needed
    for a brand new feature.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Accept FoundryChatClient instead of raw AsyncOpenAI
    
    FoundryEvals now takes client: FoundryChatClient as its primary
    parameter instead of openai_client: AsyncOpenAI.  The builtin.*
    evaluators require a Foundry endpoint, so the type should reflect that.
    
    - FoundryEvals.__init__: client: FoundryChatClient replaces openai_client
    - evaluate_traces / evaluate_foundry_target: same change
    - _resolve_openai_client: extracts .client from FoundryChatClient
    - project_client fallback retained for standalone functions
    - All samples updated to construct FoundryChatClient and pass as client=
    - Tests updated (openai_client= → client=)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove implicit 60s upper bound on poll interval
    
    If a developer sets a higher poll_interval, respect it. Only clamp
    to remaining time and enforce a 1s minimum for rate-limit protection.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove 1s floor on poll interval — let the developer control it
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Update python/samples/05-end-to-end/evaluation/foundry_evals/.env.example
    
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
    
    * Update python/samples/02-agents/evaluation/evaluate_agent.py
    
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
    
    * Address eavanvalkenburg review (round 2) on Python eval PR
    
    - Rename model_deployment -> model across FoundryEvals and all samples
    - Make model param optional, resolves from client.model
    - Convert EvalResults from dataclass to regular class
    - Remove deprecated evaluate_response() function
    - Refactor splitters: BUILT_IN_SPLITTERS dict + standalone functions
    - Change per_turn_items from classmethod to staticmethod
    - Simplify EvalCheck type alias to use Awaitable[CheckResult]
    - Remove errored property from EvalResults
    - Remove default value from Evaluator protocol eval_name
    - Rename assert_passed -> raise_for_status, add EvalNotPassedError
    - Type agent param as SupportsAgentRun | None
    - Fix Arguments docstring
    - Update __init__.py exports
    - Update all tests and samples
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Move FoundryEvals to foundry package, split tool eval sample
    
    - Move _foundry_evals.py from azure-ai to foundry package
    - Move test_foundry_evals.py to foundry/tests/
    - Update lazy re-exports in agent_framework.foundry namespace
    - Update .pyi type stubs
    - All samples now import from agent_framework.foundry
    - Split tool-call evaluation into evaluate_tool_calls_sample.py
    - Fix all_passed to check errored count from result_counts
    - Fix raise_for_status to include errored item details
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Auto-create FoundryChatClient from env vars when no client provided
    
    FoundryEvals() now works zero-config when FOUNDRY_PROJECT_ENDPOINT and
    FOUNDRY_MODEL environment variables are set. Auto-creates a FoundryChatClient
    under the hood, matching the established env var pattern.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pyright errors: remove dead _normalize_queries, suppress EvalAPIError check
    
    - Remove unused _normalize_queries function and its tests
    - Add pyright ignore for EvalAPIError None check (defensive guard)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Support multimodal image content in eval pipeline
    
    Add image (data/uri) content handling to AgentEvalConverter.convert_message()
    so that Content.from_data() and Content.from_uri() image payloads are
    preserved as input_image parts in the Foundry evaluator format.
    
    - Handle Content type='data' and type='uri' → emit input_image parts
    - Add 6 unit tests for image content through convert_message/convert_messages
    - Add integration test verifying images flow through EvalItem → JSONL path
    - Add evaluate_multimodal.py sample demonstrating local image eval
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address remaining review comments
    
    - Fix project_client docstring to say async-only (not sync/async)
    - Add builtin evaluator name validation warning in _resolve_evaluator
    - Replace getattr with typed attribute access in _poll_eval_run,
      _extract_result_counts, _extract_per_evaluator, _fetch_output_items
    - Remove cast import from _foundry_evals (no longer needed)
    - Tighten _coerce_result: honour explicit 'passed' when both 'score'
      and 'passed' are present; remove performative cast
    - Fix self_reflection sample: add env file existence check
    - Fix traces sample: correct Pattern 2 section label
    - Update all Foundry eval samples to FoundryChatClient + FOUNDRY_MODEL
      (remove AIProjectClient + AZURE_AI_MODEL_DEPLOYMENT_NAME pattern)
    - Add eval_name and OpenAI client docs to FoundryEvals docstring
    - Update test mocks to match typed SDK objects (_MockResultCounts)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix ruff lint errors (E501, SIM108, SIM102)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pyright errors: type-narrow dict to dict[str, Any], add ignore comments
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Replace ConversationSplitter type alias with Protocol
    
    ConversationSplitter is now a runtime-checkable Protocol with a named
    'conversation' parameter, making the expected signature self-documenting.
    
    ConversationSplit enum members gain a __call__ method so they satisfy
    the protocol directly -- ConversationSplit.LAST_TURN(conversation) works.
    
    This simplifies _split_conversation from an isinstance dispatch to a
    single split(conversation) call.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Standardize on AZURE_AI_MODEL_DEPLOYMENT_NAME and fix Unicode in samples
    
    - Replace FOUNDRY_MODEL with AZURE_AI_MODEL_DEPLOYMENT_NAME in all
      eval samples to match repo convention
    - Replace Unicode symbols with ASCII equivalents in all eval sample
      print statements to avoid cp1252 encoding errors on Windows
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Update python/samples/03-workflows/evaluation/evaluate_workflow.py
    
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
    
    * Apply suggestions from code review
    
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
    
    * Rename ADR 0020 to 0023 (foundry evals integration)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
  • Python: Update Python Packages for rc6 (#4979)
    * python package update
    
    * small fix
  • Python: [BREAKING] Remove deprecated kwargs compatibility paths (#4858)
    * [BREAKING] Remove deprecated kwargs compatibility paths
    
    Remove the deprecated kwargs compatibility shims across core agents, clients, tools, middleware, and telemetry.
    
    Keep workflow kwargs behavior intact in this branch and follow up separately in #4850.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix PR CI fallout for kwargs removal
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updates
    
    * Fix Azure AI CI fallout
    
    Remove the stale _get_current_conversation_id override from the Azure AI client after the OpenAI base helper was deleted.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fixed new classes
    
    * Fix Assistants deprecated import gating
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix integration replay regressions
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Switch multi-agent hosting samples to Azure chat completions
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Simplify Azure multi-agent sample config
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix broken samples for GitHub Copilot, declarative, and Responses API (#4915)
    * Python: Fix broken samples for GitHub Copilot, declarative, and Responses API
    
    - Add missing on_permission_request handler to github_copilot_basic and
      github_copilot_with_session samples (required by copilot SDK)
    - Increase timeout for remote MCP query in github_copilot_with_mcp sample
    - Soften session isolation claim in github_copilot_with_session sample
    - Fix inline_yaml sample: pass project_endpoint via client_kwargs instead
      of relying on YAML connection block (AzureAIClient expects
      project_endpoint, not endpoint)
    - Handle raw JSON schemas in Responses client _convert_response_format
      so declarative outputSchema works with the Responses API
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Improve raw JSON schema detection heuristic and add tests
    
    - Broaden raw schema detection to handle anyOf, oneOf, allOf, $ref, $defs
      keywords and JSON Schema primitive types, not just 'properties'
    - Apply same raw schema handling to azure-ai _shared.py for consistency
    - Add unit tests for both openai and azure-ai response_format conversion
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • [BREAKING] Python: fix OpenAI Azure routing and provider samples (#4925)
    * Python: fix OpenAI Azure routing and provider samples
    
    Prefer OpenAI when OPENAI_API_KEY is present unless Azure is explicitly requested. Clarify constructor docs, keep deprecated Azure wrappers compatible with stricter settings validation, and refresh the provider samples and tests to use the current client patterns.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix bandit
    
    * Python: align OpenAI embedding Azure routing
    
    Extend the shared OpenAI-vs-Azure routing and credential behavior to the embedding client, add Azure embedding regression coverage, and refresh the embedding samples to use the generic client path.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: fix embedding client pyright check
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: thin OpenAI embedding wrapper
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: document embedding overload routing
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: fix callable OpenAI key routing
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: fix Azure credential routing tests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: address OpenAI review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: narrow Azure routing markers
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: refine OpenAI model fallback order
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: narrow Azure deployment docs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: remove embedding routing wording
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: run embedding Azure integration tests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * changed variable name
    
    * Python: expand OpenAI package README
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * clarified readme
    
    * Python: fix Azure OpenAI integration setup
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: correct Azure integration env mapping
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated code to fix int tests
    
    * test updates
    
    * test fix
    
    * fix test setup
    
    * updates to tests and setup
    
    * remove openai assistants int tests
    
    * improvements in int tests
    
    * fix env var
    
    * fix env vars
    
    * fix azure responses test
    
    * trigger actions
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Bump flatted from 3.3.3 to 3.4.2 in /python/packages/devui/frontend (#4805)
    Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.3 to 3.4.2.
    - [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2)
    
    ---
    updated-dependencies:
    - dependency-name: flatted
      dependency-version: 3.4.2
      dependency-type: indirect
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Python: Support structuredContent in MCP tool results and fix sampling options type (#4763)
    * Support MCP sampling tools capability (#4625)
    
    Forward systemPrompt, tools, and toolChoice from MCP sampling requests
    to the chat client's get_response() call. Also advertise the
    sampling.tools capability to MCP servers when a client is configured.
    
    - Pass SamplingCapability with tools support to ClientSession
    - Convert systemPrompt to instructions in options
    - Convert MCP Tool objects to FunctionTool instances for options
    - Map MCP ToolChoice.mode to tool_choice in options
    - Add tests for all new behaviors and update existing sampling tests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix #4625: Support MCP sampling tool with proper typing and structured content
    
    - Fix mypy error by typing sampling callback options as ChatOptions[None]
      instead of dict[str, Any], and importing ChatOptions from _types
    - Handle structuredContent from CallToolResult in _parse_tool_result_from_mcp,
      serializing it as JSON text Content when present
    - Add tests for structuredContent parsing (with and without regular content)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix lint: add author to TODO comment
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4625: remove default=str, add edge-case tests
    
    - Remove default=str from json.dumps for structuredContent to fail fast
      on non-JSON-serializable values instead of silently converting
    - Add test for non-JSON-serializable structuredContent (TypeError)
    - Add tests for empty systemPrompt ('') and empty tools list ([]) edge
      cases in sampling callback
    - Expand TODO comment noting list[Content] return type constraint for
      future result_type support
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Sanitize sampling callback error to avoid leaking internals (#4625)
    
    Log exception details at DEBUG level instead of including them in the
    ErrorData message returned to the MCP server, which may be untrusted.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4625: move params to options, restore error info
    
    - Remove stale TODO comment about response_format (ChatOptions already has it)
    - Restore {ex} in sampling callback error message for useful debugging info
    - Set structuredContent as additional_property on Content for structured access
    - Move temperature, max_tokens, stop into options dict (not top-level kwargs)
    - Only set temperature when provided (not all models support it)
    - Add tests for generation params in options and temperature omission
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix MCP sampling callback and structured content error handling (#4625)
    
    - Guard max_tokens like temperature: only set when not None, so options
      can properly evaluate to None when all params are absent
    - Wrap json.dumps of structuredContent in try/except to fall back to
      str() for non-serializable values instead of propagating TypeError
    - Extract test_connect_sampling_capabilities_with_client into its own
      test function so pytest can discover it independently
    - Add test for max_tokens=None omission from options
    - Update structured content non-serializable test to expect fallback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4625: review comment fixes
    
    * Fix MCP and Azure validation regressions
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Include reasoning messages in MESSAGES_SNAPSHOT events (#4844)
    * Include reasoning messages in MESSAGES_SNAPSHOT (#4843)
    
    FlowState now tracks reasoning messages emitted during a run.
    _emit_text_reasoning() persists reasoning (including encrypted_value)
    into flow.reasoning_messages, and _build_messages_snapshot() appends
    them to the final MESSAGES_SNAPSHOT event.
    
    Changes:
    - Add reasoning_messages field to FlowState
    - Update _emit_text_reasoning() to accept optional flow parameter
    - Include reasoning_messages in _build_messages_snapshot()
    - Add 'reasoning' to ALLOWED_AGUI_ROLES so normalize_agui_role()
      preserves the role through snapshot round-trips
    - Skip reasoning messages in agui_messages_to_agent_framework() since
      they are UI-only state and should not be forwarded to LLM providers
    - Add regression tests for snapshot emission, encrypted value
      preservation, and multi-turn round-trip with reasoning
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Include reasoning messages in MESSAGES_SNAPSHOT events
    
    Fixes #4843
    
    * Fix PR review feedback for reasoning persistence (#4843)
    
    - Accumulate reasoning text per message_id (append deltas) instead of
      storing only the current chunk, matching flow.accumulated_text pattern
    - Use camelCase encryptedValue in snapshot JSON to match AG-UI protocol
      conventions (toolCallId, encryptedValue)
    - Normalize snake_case encrypted_value to encryptedValue in
      agui_messages_to_snapshot_format for input compatibility
    - Update normalize_agui_role docstring to include reasoning role
    - Add tests for incremental reasoning accumulation and key normalization
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4843: Python: agent-framework-ag-ui: include reasoning messages in MESSAGES_SNAPSHOT
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix streaming path to emit mcp_server_tool_result on output_item.done instead of output_item.added (#4821)
    * Fix streaming path to deliver mcp_server_tool_result content (#4814)
    
    Remove premature mcp_server_tool_result emission from the
    response.output_item.added/mcp_call handler — at that point the MCP
    server has not yet responded and output is always None.
    
    Add a handler for response.mcp_call.completed that emits
    mcp_server_tool_result with the actual tool output, matching the
    non-streaming path behavior.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix streaming path to deliver mcp_server_tool_result content (#4814)
    
    Stop eagerly emitting mcp_server_tool_result on response.output_item.added
    (when output is always None). Instead, handle response.output_item.done for
    mcp_call items, which carries the full McpCall with populated output.
    
    This matches the non-streaming path which guards with 'if item.output is not
    None' before emitting the result.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix test docstring to match actual implementation event name
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: call_id fallback and raw_representation consistency (#4814)
    
    - Add call_id fallback in response.output_item.done mcp_call handler to
      match the output_item.added handler pattern
    - Use done_item instead of event for raw_representation to keep
      consistent with other output_item branches and non-streaming path
    - Add test for call_id fallback when id attribute is missing
    - Add raw_representation assertions to existing done handler tests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: call_id fallback for non-streaming path and test coverage (#4814)
    
    - Apply defensive call_id fallback (getattr with id/call_id/empty) to
      non-streaming mcp_call path for consistency with streaming path
    - Add raw_representation assertion to call_id fallback test
    - Add test for empty-string fallback when neither id nor call_id exist
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix A2AAgent to surface message content from in-progress TaskStatusUpdateEvents (#4798)
    * Fix A2AAgent dropping message content from in-progress TaskStatusUpdateEvents (#4783)
    
    _updates_from_task() returned [] for working-state tasks when
    background=False, silently discarding all intermediate message content
    from task.status.message. Now extracts and yields message parts from
    in-progress status updates during streaming.
    
    Also fixed MockA2AClient.send_message to yield all queued responses
    (enabling multi-event streaming tests) and added text parameter to
    add_in_progress_task_response for tests that need status messages.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix: gate intermediate status updates behind emit_intermediate flag and add missing test coverage
    
    - Add emit_intermediate parameter to _updates_from_task and _map_a2a_stream
    - Thread stream flag from run() so only streaming callers see intermediate updates
    - Add IN_PROGRESS_TASK_STATES guard to emit_intermediate condition
    - Add role parameter to test helper add_in_progress_task_response
    - Add clarifying comment on MockA2AClient.send_message batch semantics
    - Add tests for user role mapping, background precedence, non-streaming behavior,
      terminal task with no artifacts, and empty parts edge case
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: [BREAKING] Reduce core dependencies and simplify optional integrations (#4904)
    * improved dependencies and some fixes
    
    * fix for mypy
    
    * improve mcp
  • Python: [BREAKING] Python: Provider-leading client design & OpenAI package extraction (#4818)
    * Python: Provider-leading client design & OpenAI package extraction
    
    Major refactoring of the Python Agent Framework client architecture:
    
    - Extract OpenAI clients into new `agent-framework-openai` package
    - Core package no longer depends on openai, azure-identity, azure-ai-projects
    - Rename clients for discoverability: OpenAIResponsesClient → OpenAIChatClient,
      OpenAIChatClient → OpenAIChatCompletionClient
    - Unify `model_id`/`deployment_name`/`model_deployment_name` → `model` param
    - New FoundryChatClient for Azure AI Foundry Responses API
    - New FoundryAgent/FoundryAgentClient for connecting to pre-configured Foundry agents
    - Remove OpenAIBase/OpenAIConfigMixin from non-deprecated client MRO
    - Deprecate AzureOpenAI* clients, AzureAIClient, OpenAIAssistantsClient
    - Reorganize samples: azure_openai+azure_ai+azure_ai_agent → azure/
    - ADR-0020: Provider-Leading Client Design
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: missing Agent imports in samples, .model_id → .model in foundry_local sample
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: CI failures — mypy errors, coverage targets, sample imports
    
    - azure-ai mypy: add type ignores for TypedDict total=, model arg, forward ref
    - Coverage: replace core.azure/openai targets with openai package target
    - project_provider: add type annotation for opts dict
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: populate openai .pyi stub, fix broken README links, coverage targets
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fixes
    
    * updated observabilitty
    
    * reset azure init.pyi
    
    * fix errors
    
    * updated adr number
    
    * fix foundry local
    
    * fixed not renamed docstrings and comments, and added deprecated markers to old classes
    
    * fix tests and pyprojects
    
    * fix test vars
    
    * updated function tests
    
    * update durable
    
    * updated test setup for functions
    
    * Fix Foundry auth in workflow samples
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Stabilize Python integration workflows
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Update hosting samples for Foundry
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Trigger full CI rerun
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Trigger CI rerun again
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * trigger rerun
    
    * trigger rerun
    
    * fix for litellm
    
    * undo durabletask changes
    
    * Move Foundry APIs into foundry namespace
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix Foundry pyproject formatting
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Split provider samples by Foundry surface
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Restore hosting sample requirements
    
    Also fix the Foundry Local sample link after the provider sample move.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated tests
    
    * udpated foundry integration tests
    
    * removed dist from azurefunctions tests
    
    * Use separate Foundry clients for concurrent agents
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix client setup in azfunc and durable
    
    * disabled two tests
    
    * updated setup for some function and durable tests
    
    * improved azure openai setup with new clients
    
    * ignore deprecated
    
    * fixes
    
    * skip 11
    
    * remove openai assistants int tests
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix PydanticSchemaGenerationError when using from __future__ import annotations with @tool (#4822)
    * Fix PydanticSchemaGenerationError with PEP 563 annotations in @tool
    
    _resolve_input_model used raw param.annotation from inspect.signature(),
    which returns string annotations when 'from __future__ import annotations'
    is active (PEP 563). This caused Pydantic's create_model to fail for
    complex types like Optional[int] or FunctionInvocationContext.
    
    Use typing.get_type_hints() to resolve annotations to actual types before
    passing them to create_model, matching the approach already used by
    _discover_injected_parameters.
    
    Fixes #4809
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Remove reproduction report and unused test imports
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(tests): strengthen PEP 563 regression tests per review feedback (#4809)
    
    - Verify type correctness in schema assertions (not just key presence)
    - Fix ctx annotation to FunctionInvocationContext | None for type consistency
    - Add test for Optional[CustomType] pattern (original bug trigger)
    - Add test for get_type_hints() fallback with unresolvable forward refs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Address review feedback for #4809: Python: [Bug]: PydanticSchemaGenerationError in FunctionInvocationContext
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • [BREAKING] Python: Add context mode to AgentExecutor (#4668)
    * Add context mode to AgentExecutor
    
    * Fix unit tests
    
    * Address comments
    
    * Address comments
    
    * REvise context mode and add tests
    
    * Add chain config to sequential builder
    
    * Add sample
    
    * Fix pipeline
    
    * Address comments
    
    * Address comments
  • Python: avoid duplicate agent response telemetry (#4685)
    * Python: avoid duplicate agent response telemetry
    
    * Python: conditionally suppress duplicate agent telemetry
    
    * Simplify telemetry ownership tracking
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Aggregate token usage from inner chat spans on invoke_agent span
    
    The invoke_agent span now carries the aggregated input/output token
    counts from all inner chat completion spans that occur during an agent
    run. Previously, when inner ChatTelemetryLayer spans captured usage,
    the outer AgentTelemetryLayer skipped setting usage entirely to avoid
    duplication. Now a new INNER_ACCUMULATED_USAGE context variable tracks
    cumulative usage across all inner completions, and the agent span
    always reports the total.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Deprecate Azure AI v1 (Persistent Agents API) helper methods (#4804)
    * Deprecate Azure AI v1 (Persistent Agents API) helper methods
    
    Add DeprecationWarning to v1 classes and functions that have been
    superseded by the v2 (Projects/Responses) API:
    
    - AzureAIAgentsProvider -> use AzureAIProjectAgentProvider
    - AzureAIAgentClient -> use AzureAIClient
    - AzureAIAgentOptions -> use AzureAIProjectAgentOptions
    - to_azure_ai_agent_tools() -> use to_azure_ai_tools()
    - from_azure_ai_agent_tools() -> use from_azure_ai_tools()
    - AzureAIAgentClient static tool factory methods -> use AzureAIClient equivalents
    
    All v1 components still function but emit warnings to guide migration.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add deprecation warnings to AzureAIAgentsProvider methods
    
    Mark create_agent(), get_agent(), and as_agent() as deprecated
    individually, pointing to AzureAIProjectAgentProvider equivalents.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Bump Python version to 1.0.0rc5 and 1.0.0b260319 for a release. (#4807)
    * Bump Python version to 1.0.0rc5 and 1.0.0b260319 for a release.
    
    * update missed pkg versions
    
    * Update changelog
  • Python: Emit tool call events in GitHubCopilotAgent streaming (#4711)
    * Emit tool call events in GitHubCopilotAgent streaming
    
    _stream_updates now yields FunctionCallContent for TOOL_EXECUTION_START
    and FunctionResultContent for TOOL_EXECUTION_COMPLETE events from the
    Copilot SDK session. This enables DevUI and other consumers to display
    tool calls during streaming agent execution. Previously only ASSISTANT_MESSAGE_DELTA, SESSION_IDLE, and SESSION_ERROR
    were handled — tool execution events were silently dropped.
    
    Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
    
    * Add some tests
    
    Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
    
    * Respond to feedback
    
    Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
    
    * Fix TOOL_EXECUTION_COMPLETE to use correct SDK types
    
    - Read result text from session_events.Result.content (not ToolResult.text_result_for_llm)
    - Read failure state from event.data.success/error (not result_obj.result_type/error)
    - Handle ErrorClass.message and plain string errors
    - Update tests to use session_events.Result and ErrorClass
    - Add tests for string errors, success-with-error, and COMPLETE missing fields
    
    Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
    
    ---------
    
    Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
  • Python: [BREAKING] Refactor middleware layering and split Anthropic raw client (#4746)
    * [BREAKING] Refactor middleware layering and raw clients
    
    Reorder chat client layers so function invocation wraps chat middleware, and chat middleware stays outside telemetry while still running for each inner model call. Add middleware pipeline caching, refresh docs and samples, and split Anthropic into raw and public clients to match the standard layering model.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Tighten typing ignores in ancillary modules
    
    Add targeted typing ignores in workflow visualization and lab modules so pyright stays clean alongside the middleware refactor work.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix categorize_middleware to unpack tuple/Sequence and use relative MRO assertions
    
    - Broaden isinstance check in categorize_middleware from list to Sequence
      so tuples and other Sequence types are properly unpacked instead of
      being appended as a single item.
    - Replace fragile hardcoded MRO index assertions in anthropic test with
      relative ordering via mro.index().
    - Add regression tests for categorize_middleware with tuple, list, and
      None inputs.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix middleware string decomposition, add middleware param to FunctionInvocationLayer, and add tests (#4710)
    
    - Guard categorize_middleware Sequence check against str/bytes to prevent
      character-by-character decomposition of accidentally passed strings
    - Add explicit middleware parameter to FunctionInvocationLayer.get_response
      and merge it into client_kwargs before categorization, fixing the
      inconsistency where only OpenAIChatClient supported this parameter
    - Add assertions that RawAnthropicClient does not inherit convenience layers
    - Add chat middleware cache test with non-empty base middleware
    - Add tests for single unwrapped middleware item and string input
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Apply pre-commit auto-fixes
    
    * Address review feedback for #4710: review comment fixes
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Copilot <copilot@github.com>
  • Python: Emit TOOL_CALL_RESULT events when resuming after tool approval (#4758)
    * Emit TOOL_CALL_RESULT events on approval resume (#4589)
    
    When a tool call is approved via the interrupt/resume flow,
    _resolve_approval_responses executes the tool and injects the result
    into the messages array, but no TOOL_CALL_RESULT SSE event was yielded
    to the client.
    
    Changes:
    - _resolve_approval_responses now returns the list of resolved
      function_result Content objects instead of None
    - run_agent_stream yields ToolCallResultEvent for each resolved
      approval result after RunStartedEvent is emitted
    - Add ToolCallResultEvent to ag_ui.core imports in _agent_run.py
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * fix(ag-ui): address PR review feedback for #4589
    
    1. _resolve_approval_responses now returns only approved results (not
       rejections) so TOOL_CALL_RESULT events are emitted only for executed
       tools. Rejection results are still written into message history.
    
    2. Emit resolved TOOL_CALL_RESULT events in the no-updates fallback
       RUN_STARTED path so approval results are never lost.
    
    3. Rewrite tests to use real FunctionTool with func and
       approval_mode='always_require' via StubAgent default_options,
       verifying actual tool execution output in TOOL_CALL_RESULT content.
       Added test for rejection not emitting TOOL_CALL_RESULT.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix #4589: clean up approval resolution and add missing tests
    
    - Extract duplicated TOOL_CALL_RESULT emission block into
      _make_approval_tool_result_events helper to prevent drift
    - Remove dead rejection_results construction in _resolve_approval_responses;
      _replace_approval_contents_with_results already handles rejections inline
    - Pass only approved_results (not all_results) to clarify the contract
    - Add mixed approve/reject test validating the core splitting logic
    - Add zero-updates test covering the no-updates fallback emission path
    - Add direct unit test for _resolve_approval_responses return value
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Fix import sorting lint error in test_approval_result_event.py
    
    Add blank line between first-party and third-party import groups
    to satisfy ruff I001 rule.
    
    Fixes #4589
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Emit AG-UI events for MCP tool calls, results, and text reasoning (#4760)
    * Python: Emit AG-UI events for MCP tool calls, results, and text reasoning
    
    Fixes #4213 — `_emit_content()` in the AG-UI layer only handled `text`,
    `function_call`, `function_result`, `function_approval_request`, `usage`,
    and `oauth_consent_request` content types. Foundry MCP content types
    (`mcp_server_tool_call`, `mcp_server_tool_result`) and `text_reasoning`
    fell through unhandled, producing no SSE events for AG-UI consumers.
    
    Added three new handler functions wired into `_emit_content()`:
    
    - `_emit_mcp_tool_call`: emits TOOL_CALL_START + TOOL_CALL_ARGS and
      tracks in FlowState for MESSAGES_SNAPSHOT inclusion
    - `_emit_mcp_tool_result`: emits TOOL_CALL_END + TOOL_CALL_RESULT with
      full FlowState cleanup mirroring `_emit_tool_result`
    - `_emit_text_reasoning`: emits the protocol-defined reasoning event
      sequence (ReasoningStart → MessageStart → MessageContent → MessageEnd
      → ReasoningEnd) with ReasoningEncryptedValueEvent for protected_data
    
    * Add HTTP round-trip tests for MCP tool and reasoning SSE events
    
    Exercises the full POST → SSE bytes → parse → validate pipeline for
    mcp_server_tool_call, mcp_server_tool_result, text_reasoning, and
    ReasoningEncryptedValueEvent content through FastAPI TestClient.
    
    * Fix _emit_mcp_tool_result missing predictive_handler support (#4213)
    
    - Add predictive_handler parameter to _emit_mcp_tool_result and mirror
      the apply_pending_updates + StateSnapshotEvent block from _emit_tool_result
    - Forward predictive_handler from _emit_content to _emit_mcp_tool_result
    - Add assertion for stored arguments in MCP tool call test
    - Add test for predictive handler state snapshot after MCP tool result
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Refactor MCP tool emit functions and add missing tests (#4213)
    
    - Extract _emit_tool_result_common shared helper to eliminate duplication
      between _emit_tool_result and _emit_mcp_tool_result
    - Remove server_name prefix from tool_call_name in _emit_mcp_tool_call;
      display_name now equals tool_name directly
    - Add test for tool_name fallback to 'mcp_tool' when tool_name is None
    - Add test for output=None fallback to empty string in _emit_mcp_tool_result
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4213: review comment fixes
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Support detail field in OpenAI Chat API image_url payload (#4756)
    * Support detail field in OpenAI image_url payload (#4616)
    
    Include the optional 'detail' field from Content.additional_properties
    when building image_url payloads for the OpenAI Chat API, matching the
    existing pattern used for 'filename' in document file payloads.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Remove reproduction report
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Simplify detail extraction from additional_properties (#4616)
    
    - Remove unnecessary hasattr check; additional_properties is always
      initialized as a dict on Content instances.
    - Use 'is not None' instead of truthy check to be more precise.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Remove detail allowlist in chat client to align with responses client
    
    Replace the strict allowlist check ('low', 'high', 'auto') with an
    isinstance(detail, str) check so that any valid string detail value is
    passed through to OpenAI. This aligns the chat client behavior with the
    responses client, which passes detail through unconditionally.
    
    Also add test coverage for:
    - Future/unknown string detail values being passed through
    - Data URI images (covering the 'data' branch of the match)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix MCP tool schema normalization for zero-argument tools missing 'properties' key (#4771)
    * Fix zero-argument MCP tool schema missing 'properties' key (#4540)
    
    MCP servers for zero-argument tools (e.g. matlab-mcp-core-server's
    detect_matlab_toolboxes) declare inputSchema as {"type": "object"}
    without a "properties" key. OpenAI's API requires "properties" to
    be present on object schemas, causing a 400 invalid_request_error.
    
    Normalize inputSchema at MCP ingestion in load_tools() to inject an
    empty "properties": {} when it is missing from object-type schemas.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4540: improve test robustness and add defensive guard
    
    - Look up loaded functions by name instead of index to avoid brittle
      ordering assumptions
    - Add negative-path test cases: non-object schema (type: string) and
      empty schema ({}) to verify guard clause skips them correctly
    - Assert original inputSchema dicts are not mutated by load_tools()
    - Add defensive guard for tool.inputSchema being None
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4540: Python: [Bug]: Local stdio MCP works for calculator but fails for official matlab-mcp-core-server on LM Studio /v1/responses
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix A2AAgent to invoke context providers before and after run (#4757)
    * Fix A2AAgent to invoke context providers before and after run
    
    A2AAgent.run() bypassed the context provider lifecycle (before_run/after_run)
    that BaseAgent defines as a contract for all agents. This caused A2AAgent to
    violate the semantic definition of BaseAgent, resulting in inconsistency with
    other agent implementations.
    
    The fix follows the same pattern used by WorkflowAgent:
    - Create SessionContext and run before_run on all context providers before
      processing the A2A stream
    - Collect response updates and run after_run on all context providers after
      the stream is fully consumed
    - Auto-create a session when context providers are configured but no session
      is explicitly passed
    
    Fixes #4754
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Remove reproduction report from repository
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback for #4754
    
    - Validate messages when no continuation_token: raise ValueError if
      normalized_messages is empty, preventing IndexError on messages[-1]
    - Import BaseContextProvider/SessionContext from public agent_framework
      package instead of internal agent_framework._sessions module
    - Add test for ValueError on run(None) without continuation_token
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Improve test coverage for empty-messages guard in A2AAgent.run (#4754)
    
    - Parameterize test to cover both messages=None and messages=[] inputs
    - Add test verifying run(None, continuation_token=...) does not raise
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Aggregate token usage across tool-call loop iterations in invoke_agent span (#4739)
    * Fix invoke_agent span to aggregate token usage across LLM calls (#4062)
    
    The FunctionInvocationLayer._get_response() loop was overwriting the
    response on each iteration, so usage_details only reflected the last
    chat completion call. Now tracks aggregated_usage across all iterations
    using add_usage_details() and sets it on the returned response.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Remove reproduction report artifact
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Apply pre-commit auto-fixes
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Simplify Python Poe tasks and unify package selectors (#4722)
    * updated automation tasks and commands, with alias for the time being
    
    * Restore aggregate test exclusions
    
    Preserve the legacy all-tests scope for test --all by excluding lab and devui from the default aggregate sweep, while still allowing explicit package selection. Also ignore hidden/generated test directories such as .mypy_cache during aggregate discovery.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated versions in pre-commit
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix ENABLE_SENSITIVE_DATA env var ignored when set after module import (#4743)
    * Python: Re-read env vars in configure_otel_providers and enable_instrumentation (#4119)
    
    Fix ENABLE_SENSITIVE_DATA and VS_CODE_EXTENSION_PORT env vars being ignored
    when load_dotenv() runs after module import. The module-level
    OBSERVABILITY_SETTINGS singleton cached env state at import time, and
    configure_otel_providers() / enable_instrumentation() never re-read from
    os.environ when parameters were None.
    
    Both functions now construct a fresh ObservabilitySettings() to pick up
    current env vars when explicit parameters are not provided, matching the
    existing behavior of the env_file_path branch.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback for #4119: avoid throwaway ObservabilitySettings
    
    - Add _read_bool_env/_read_int_env helpers to read env vars without
      constructing a full ObservabilitySettings (which calls create_resource())
    - Replace ObservabilitySettings() in enable_instrumentation() and
      configure_otel_providers() else-branch with direct env reads
    - Add enable_console_exporters parameter to configure_otel_providers()
      for override parity with enable_sensitive_data and vs_code_extension_port
    - Propagate _resource and _executed_setup in the non-env_file_path branch
    - Make existing tests hermetic (clear VS_CODE_EXTENSION_PORT and
      ENABLE_CONSOLE_EXPORTERS env vars)
    - Add tests: enable_console_exporters env refresh, explicit param overrides
      for both enable_instrumentation() and configure_otel_providers()
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address remaining review feedback for #4119
    
    - Refresh enable_console_exporters in enable_instrumentation() for
      consistency with configure_otel_providers(), so env var changes
      after import are picked up by both public API functions
    - Make test_configure_otel_providers_reads_env_vs_code_port hermetic
      by clearing ENABLE_CONSOLE_EXPORTERS from the environment
    - Add test_enable_instrumentation_reads_env_console_exporters to
      cover the new refresh behavior
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove unconditional enable_console_exporters overwrite from enable_instrumentation() (#4119)
    
    enable_instrumentation() is documented as not configuring exporters, so
    managing enable_console_exporters there was a leaky abstraction. The
    unconditional _read_bool_env call silently reset the value to False when
    ENABLE_CONSOLE_EXPORTERS was absent from env, clobbering any value
    previously set by configure_otel_providers(enable_console_exporters=True).
    
    - Remove the unconditional overwrite line from enable_instrumentation()
    - Replace test_enable_instrumentation_reads_env_console_exporters with
      test_enable_instrumentation_does_not_touch_console_exporters
    - Add regression test: enable_instrumentation() does not clobber a
      previously configured enable_console_exporters value
    - Add test: explicit enable_sensitive_data param still leaves
      enable_console_exporters untouched
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix missing methods on the Content class in durable tasks (#4738)
    * Fix Content serialization in DurableAgentStateUnknownContent (#4719)
    
    DurableAgentStateUnknownContent.from_unknown_content() stored raw Content
    objects without converting them to dicts, causing json.dumps to fail in
    Azure Durable Functions' entity state serialization. This affected content
    types not explicitly handled (e.g., mcp_server_tool_call/result).
    
    The fix converts Content objects to dicts via to_dict() when storing in
    DurableAgentStateUnknownContent, and restores them via Content.from_dict()
    in to_ai_content().
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add to_json and from_json methods to Content class (#4719)
    
    Add to_json() and from_json() methods to the Content class to match the
    serialization interface provided by SerializationMixin on other model classes.
    Also fix pre-existing pyright type errors in durabletask's
    DurableAgentStateUnknownContent.to_ai_content().
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review: add type guard, remove to_json, add fallback, and tests
    
    - Remove Content.to_json() per reviewer request (comment 3)
    - Add type guard in Content.from_json() for non-dict JSON (comments 1, 4)
    - Wrap json.JSONDecodeError as ValueError for consistent exception contract
    - Add try/except fallback in to_ai_content() for invalid Content dicts (comment 5)
    - Add test_content_to_dict_exclude_none and test_content_to_dict_exclude_fields (comment 2)
    - Add test_unknown_content_to_ai_content_fallback_on_invalid_type_dict (comment 5)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Address review feedback for #4719: review comment fixes
    
    * Remove Content.from_json, move logic to consuming code (#4719)
    
    Remove the from_json convenience method from Content class per review
    feedback. This is the same trivial json.loads + from_dict wrapper as
    to_json which was already removed. Consumers should call json.loads
    and Content.from_dict directly.
    
    Update tests to use Content.from_dict(json.loads(...)) pattern and
    remove from_json-specific error handling tests (those errors are
    already covered by json.loads and Content.from_dict).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Reduce Azure chat client import overhead (#4744)
    * Reduce Azure chat client import overhead
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix Azure chat client type annotations and add _parse_text_from_openai tests
    
    - Move Choice and ChunkChoice imports under TYPE_CHECKING to avoid
      runtime import cost (from __future__ annotations is already present)
    - Restore proper typed signature (Choice | ChunkChoice) instead of Any
    - Add direct unit tests for _parse_text_from_openai covering:
      - Choice with message content
      - ChunkChoice with delta content
      - Refusal branch for both Choice and ChunkChoice
      - No content/no refusal returning None
      - None delta (async content filtering) returning None
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Copilot <copilot@github.com>
  • Python: Fix RUN_FINISHED.interrupt to accumulate all interrupts when multiple tools need approval (#4717)
    * Fix flow.interrupts overwrite when multiple tools need approval (#4590)
    
    Change flow.interrupts assignment to append so that all interrupt entries
    accumulate when multiple tools require approval in a single turn.
    
    Both _run_common.py and _agent_run.py used assignment (=) which caused
    each new interrupt to overwrite the previous one. Switching to append()
    ensures RUN_FINISHED.interrupt contains all pending approvals.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add test for streaming path with multiple confirm_changes interrupts (#4590)
    
    Add integration test exercising run_agent_stream with multiple predictive
    tool calls requiring confirmation. Verifies that flow.interrupts.append()
    correctly accumulates all interrupt entries and they appear in the
    RUN_FINISHED event.
    
    Also confirms FlowState already declares interrupts field with
    default_factory=list, addressing the AttributeError concern from review.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: fix thread serialization for multi-turn tool calls (#4684)
    * Python: strip fc_id from loaded history
    
    * Move fc_id replay handling into Responses client
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove unnecessary pytest asyncio marker
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add Responses integration test for fc_id replay
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * removed old arg
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: preserve A2A message context_id (#4686)
    * Python: forward A2A context_id
    
    * Avoid duplicating A2A context ids
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix _deduplicate_messages catch-all branch dropping valid repeated messages (#4716)
    * Fix _deduplicate_messages catch-all branch dropping valid repeated messages (#4682)
    
    Remove the catch-all dedup branch that used (role, hash(content_str)) as a
    dedup key. This incorrectly treated any two messages with the same role and
    identical content as duplicates, dropping valid repeated messages (e.g., a
    user saying 'yes' to confirm two separate things).
    
    The tool-specific dedup branches (tool results by call_id, assistant tool
    calls by call_id tuple) remain unchanged as they correctly identify true
    protocol-level duplicates.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: consecutive-duplicate detection for non-tool messages (#4682)
    
    - Replace blanket dedup removal with consecutive-duplicate detection:
      only skip a message if the immediately preceding message has the same
      role and content, preserving protection against upstream replays while
      allowing identical messages at different conversation points.
    - Strengthen test assertions to verify message identity and order, not
      just list length.
    - Add tests for consecutive duplicate skipping, non-consecutive
      preservation, and messages with contents=None.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Use message_id for deduplication instead of content hashing
    
    Deduplicate general messages by message_id when available, replacing
    the consecutive-duplicate content check. Two messages with the same id
    are definitively the same message (upstream replay), while identical
    content with distinct ids (e.g. repeated "yes" confirmations) is
    preserved. Messages without a message_id are always kept.
    
    * Fix message_id dedup: truthy check, content-hash fallback, log safety
    
    - Use truthy check (`if msg.message_id`) instead of `is not None` so
      empty-string IDs fall through to content-hash dedup rather than
      collapsing unrelated messages.
    - Add content-hash fallback for messages without message_id, preventing
      false negatives from integrations that don't set IDs.
    - Remove raw message_id from log format string (addresses log-injection
      surface with control characters).
    - Add tests for empty-string message_id edge cases.
    - Update existing tests to reflect content-hash dedup behavior.
    
    Fixes #4682
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: keep MCP cleanup on the owner task (#4687)
    * Python: keep MCP cleanup on owner task
    
    * Avoid MCP owner task deadlocks
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix MCP owner-task timeout tests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: normalize empty MCP tool output to null (#4683)
    * Python: normalize empty MCP tool output to null
    
    * Python: hardcode null for empty MCP output
  • Python: chore(python): improve dependency range automation (#4343)
    * chore(python): improve dependency range automation
    
    - tighten dependency bounds and coding standards guidance\n- add dependency range validation workflow, reporting, and issue automation\n- update related tests and dependency pins for compatibility
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated text and pyarrow
    
    * new lock
    
    * fixed workflow
    
    * updated deps
    
    * fix tiktoken
    
    * chore(python): refine dependency validation workflows
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(python): add high-level dependency validation comments
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * WIP
    
    * added additional comments and excludes
    
    * added dev dependency handling and workflow and updates to package ranges
    
    * added readme and simplified commands
    
    * fix markers
    
    * chore(python): address dependency review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Tighten dependency bounds, remove stale overrides, restore Python 3.10 support
    
    - Apply dependency bound policy across all packages: stable >=1.0 deps use
      >=floor,<next_major; pre-1.0/prerelease deps use validated hard-bounded ranges
    - Remove stale root tool.uv.override-dependencies (uvicorn, websockets, grpcio)
    - Lower github_copilot requires-python to >=3.10 with github-copilot-sdk gated
      behind python_version >= 3.11 marker; import raises ImportError on 3.10
    - Skip github_copilot pyright/mypy/test tasks on Python <3.11
    - Use version-conditional pyrightconfig for samples on Python 3.10
    - Add compatibility fix in core responses client for older openai typed dicts
    - Normalize uv.lock prerelease mode and refresh dev dependencies
    - Update CODING_STANDARD.md, DEV_SETUP.md, and package management skill docs
    
    Closes #902
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * small tweaks
    
    * add note in workflow
    
    * fix workflows and several versions
    
    * fix duplicate
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • [BREAKING] Python: clean up kwargs across agents, chat clients, tools, and sessions (#4581)
    * Python: clean up kwargs across agents, chat clients, tools, and sessions (#3642)
    
    Audit and refactor public **kwargs usage across core agents, chat clients,
    tools, sessions, and provider packages per the migration strategy codified
    in CODING_STANDARD.md.
    
    Key changes:
    - Add explicit runtime buckets: function_invocation_kwargs and client_kwargs
      on RawAgent.run() and chat client get_response() layers.
    - Refactor FunctionTool to prefer explicit ctx: FunctionInvocationContext
      injection; legacy **kwargs tools still work via _forward_runtime_kwargs.
    - Refactor Agent.as_tool() to use direct JSON schema, always-streaming
      wrapper, approval_mode parameter, and UserInputRequiredException
      propagation (integrates PR #4568 behavior).
    - Remove implicit session bleeding into FunctionInvocationContext; tools
      that need a session must receive it via function_invocation_kwargs.
    - Lower chat-client layers after FunctionInvocationLayer accept only
      compatibility **kwargs (client_kwargs flattened, function_invocation_kwargs
      ignored).
    - Add layered docstring composition from Raw... implementations via
      _docstrings.py helper.
    - Clean up provider constructors to use explicit additional_properties.
    - Deprecation warnings on legacy direct kwargs paths.
    - Update samples, tests, and typing across all 23 packages.
    
    Resolves #3642
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * clarified docstring
    
    * feedback fixes
    
    * Add unit tests for _docstrings.py build/apply helpers
    
    Tests cover: no docstring source, no extra kwargs, appending to existing
    Keyword Args section, inserting after Args, inserting in plain docstrings,
    multiline descriptions, ordering, and apply_layered_docstring.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add test for propagate_session TypeError on non-AgentSession values
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add tests for multi-content and empty UserInputRequiredException propagation
    
    Cover the branching logic in _try_execute_function_calls for:
    - Multiple user_input_request items in a single exception (extra_user_input_contents path)
    - Empty contents list (fallback function_result path)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add tests for DurableAIAgent.get_session forwarding service_session_id
    
    Verifies get_session correctly forwards service_session_id and session_id
    to the executor's get_new_session, replacing the removed kwargs test.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Simplify ag-ui test stub to read session from client_kwargs only
    
    Remove dual-mode detection (client_kwargs vs raw kwargs fallback) from
    the test mock. Session is now read exclusively from client_kwargs,
    matching the settled public calling convention.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated create and get sessions in durable
    
    * fixed docstrings
    
    * fix test
    
    * updated session handling
    
    * updated from main
    
    * updated tests
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix type hint for Case and Default (#3985)
    * Fix type hint for `Case` and `Default`
    
    * Add test
    
    ---------
    
    Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
  • Python: A2AAgent defaults name/description from AgentCard (#4661)
    * Python: A2AAgent defaults name/description from AgentCard
    
    When an AgentCard is provided but name/description are not explicitly
    set, A2AAgent now falls back to agent_card.name and agent_card.description.
    This avoids redundant duplication when constructing A2AAgent instances,
    especially in GroupChat orchestrations where name and description are
    essential for routing decisions.
    
    Explicit values still take precedence over card values.
    
    Fixes #4630
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Use 'is None' checks instead of truthiness for name/description fallback
    
    Ensures explicitly provided empty strings are not overridden by
    agent_card values. Adds test for the empty string edge case.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Unify tool results as Content items with rich content support (#4331)
    * feat(python): allow @tool functions to return rich content (images, audio)
    
    Add support for tool functions to return Content objects that the model can perceive natively. Closes #4272
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Anthropic logging + mypy fix
    
    * Address PR review: fix MCP ordering, fold helper into from_function_result, fix Chat client
    
    - Preserve original content order in MCP tool results instead of text-first
    - Move _build_function_result logic into Content.from_function_result()
    - Chat Completions: inject user message for rich items (API only supports string tool content)
    - Update tests for ordering and new from_function_result behavior
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Use native Responses API multi-part output, warn+omit for Chat client
    
    - Responses client: put rich items directly in function_call_output's
      output field as list (native API support) instead of user message injection
    - Chat client: warn and omit rich items (API doesn't support multi-part
      tool results), matching Ollama/Bedrock pattern
    - Unify test image: use sample_image.jpg across all integration tests
    - Add Azure OpenAI Responses integration test
    - Assert model describes house image to verify perception
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix lint: remove print statement, wrap long line
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback: bug fixes, single-pass MCP, unit tests
    
    - Add isinstance guard in from_function_result for non-Content lists
    - Fix Anthropic empty tool_content fallback to string result
    - Fix Content(type='text', text=None) edge case in parse_result
    - Rewrite MCP _parse_tool_result_from_mcp as single-pass (no index counters)
    - Add Anthropic unit tests: data image, uri image, unsupported media, all-unsupported
    - Add OpenAI Chat unit test: rich items warning and omission
    - Add OpenAI Responses unit tests: function_result with/without items
    - Add test_types tests: only-rich-items list, non-Content list fallback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pyright errors: add type ignore comments for Any list iteration
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix mypy/pyright: ensure ToolExecutionException receives str
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix lint: remove duplicate test_prepare_options_excludes_conversation_id
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor: unify all tool results into Content items
    
    * addressed copilot comments
    
    * pyright fix
    
    * small fix
    
    * comments
    
    * fix: address Copilot review - warnings, blob safety, dedup
    
    - Add warning logs when rich content is dropped in Claude agent and
      MCP server handlers (matching Chat/Bedrock/Ollama pattern)
    - Defensive blob URI construction: wrap plain base64 in data: prefix
    - Simplify Chat client _prepare_content_for_openai to use content.result
    - Simplify Responses client text-only path, remove redundant nesting
    - Add test for plain base64 blob without data: prefix
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix token double-counting in compaction and address review comments
    
    - Exclude items from _serialize_content() to prevent double-counting
      tokens when items mirrors result in function_result content
    - Add rich content warning in GitHub Copilot agent tool handler
    - Replace raw Content debug log with concise item count/type summary
    - Update stale test comments about FunctionTool.invoke return type
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • fix: omit toolConfig when tool_choice="none" in BedrockChatClient (#4535)
    Bedrock's Converse API only accepts "auto", "any", or "tool" as valid
    toolChoice keys. The previous code mapped tool_choice="none" to
    {"none": {}}, which causes a botocore.exceptions.ParamValidationError.
    
    When tool_choice="none" (set by FunctionInvocationLayer after exhausting
    max iterations), the fix now omits toolConfig entirely so the model
    won't attempt tool calls.
    
    Added tests for tool_choice="none", "auto", and "required" modes.
    
    Fixes #4529
    
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
  • Python: Fix state snapshot to use deepcopy so nested mutations are detected in durable workflow activities (#4518)
    * Use deepcopy for state snapshot to detect nested mutations (#4500)
    
    Replace dict() shallow copy with copy.deepcopy() when snapshotting
    workflow state before activity execution. The shallow copy shared
    references to nested objects (dicts, lists), so in-place mutations by
    executors were reflected in both the snapshot and live state, producing
    an empty diff and preventing state updates from propagating to
    downstream activities.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Fix state snapshot to use deepcopy so nested mutations are detected in durable workflow activities
    
    Fixes #4500
    
    * Address PR review: remove report, extract testable helpers (#4500)
    
    - Delete REPRODUCTION_REPORT.md (debugging artifact with local paths
      and raw LLM output)
    - Extract _create_state_snapshot() and _compute_state_updates() as
      module-level helpers in _app.py so tests exercise the production
      code path
    - Update TestStateSnapshotDiff to import and use production helpers
      instead of reimplementing snapshot/diff logic locally
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Add regression tests proving shallow copy bug and deep copy isolation (#4500)
    
    Add two additional tests to TestStateSnapshotDiff:
    - test_shallow_copy_would_miss_nested_mutations: reproduces the original
      bug by demonstrating that dict() (shallow copy) misses nested mutations
    - test_create_state_snapshot_isolates_nested_objects: verifies the
      production _create_state_snapshot helper creates a true deep copy
    
    These tests ensure a regression back to shallow copy would be caught.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add integration test exercising full activity code path (#4500)
    
    Address PR review comment: add test_executor_activity_detects_nested_state_mutations
    that captures the actual executor_activity function from _setup_executor_activity
    and verifies it detects in-place nested mutations. This test would fail if
    _app.py line 314 regressed from _create_state_snapshot() back to dict().
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4518: review comment fixes
    
    * Address PR review feedback for state snapshot diff
    
    - Inline _compute_state_updates logic at call site to reuse precomputed
      original_keys/current_keys sets, avoiding redundant set allocations
    - Fix test docstring to describe behavioral regression instead of
      hard-coding a specific line number
    - Use SOURCE_ORCHESTRATOR constant in integration test instead of
      literal string
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * fix: remove unused _compute_state_updates from _app.py (#4518)
    
    The function was inlined per review comment, making the module-level
    helper unused and triggering a pyright reportUnusedFunction error.
    Move the helper into the test file where it is still needed for unit
    testing the diffing logic.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Bump rollup from 4.47.1 to 4.59.0 in /python/packages/devui/frontend (#4338)
    Bumps [rollup](https://github.com/rollup/rollup) from 4.47.1 to 4.59.0.
    - [Release notes](https://github.com/rollup/rollup/releases)
    - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
    - [Commits](https://github.com/rollup/rollup/compare/v4.47.1...v4.59.0)
    
    ---
    updated-dependencies:
    - dependency-name: rollup
      dependency-version: 4.59.0
      dependency-type: indirect
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Bump minimatch from 3.1.2 to 3.1.5 in /python/packages/devui/frontend (#4337)
    Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.2 to 3.1.5.
    - [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
    - [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)
    
    ---
    updated-dependencies:
    - dependency-name: minimatch
      dependency-version: 3.1.5
      dependency-type: indirect
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Fix CWE-863: Validate function approval responses in DevUI executor (#4598)
    The DevUI /v1/responses endpoint accepts function_approval_response content
    without verifying that the request_id corresponds to a real pending approval
    request issued by the server. This allows forged approval responses to
    execute arbitrary tools with attacker-controlled arguments, bypassing
    approval_mode='always_require'.
    
    Changes:
    - Track outgoing approval requests in a server-side registry
      (_pending_approvals) keyed by request_id
    - Validate incoming approval responses against this registry; reject
      any response whose request_id was not issued by the server
    - Use server-stored function_call data (tool name, arguments, call_id)
      instead of client-supplied data when constructing the approval response
    - Consume request_ids on use (pop from registry) to prevent replay attacks
    
    Tests:
    - 8 new tests covering forged rejection, server-data enforcement,
      anti-replay, multiple independent approvals, and edge cases
    
    Co-authored-by: REDMOND\tusharmudi <tusharmudi@microsoft.com>
  • Python: Validate approval responses against server-side pending request registry (#4548)
    * Validate approval responses against server-side pending request registry
    
    * improvements
    
    * pin GHCP sdk version to non-breaking for now
    
    * Pin CHCP sdk to LKG.
    
    * really fix GHCP sdk pkg version
    
    * Fix HITL approval validation security gaps and memory leak
    
    - Validate rejected approval responses against pending_approvals registry,
      not just approved ones. Fabricated rejections without a prior request are
      now stripped from messages before reaching the LLM.
    - Bound _pending_approvals with OrderedDict + LRU eviction (max 10k) to
      prevent unbounded memory growth from abandoned approval requests.
    - Skip registration when function_call.name is None/empty; log warning
      when content.id or function_call is missing at registration time.
    - Document pending_approvals parameter in run_agent_stream docstring.
    - Add test for fabricated rejection attack scenario.
    - Assert pending approval entry is preserved after function name mismatch.
    - Pre-populate pending_approvals in rejection test for correct validation.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix function_approval_response extraction in AG-UI workflow path (#4550)
    * Extract function_approval_response from workflow messages (#4546)
    
    _extract_responses_from_messages now handles function_approval_response
    content in addition to function_result content. Previously, approval
    responses sent via the messages field were silently dropped because the
    function only checked for content.type == "function_result".
    
    The approval response is keyed by content.id and includes the approved
    status, id, and serialized function_call — consistent with how
    _coerce_content identifies approval response payloads.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Fix #4546: Update docstring and add integration tests for message-based approvals
    
    - Update _extract_responses_from_messages docstring to reflect that it
      now handles function_approval_response content in addition to
      function_result content.
    - Add integration tests for run_workflow_stream across two turns with
      approval responses provided via messages (function_approvals) rather
      than resume.interrupts, covering both approved and denied scenarios.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback for #4546
    
    - Use safer 'not .get("interrupt")' assertion instead of 'not in'
      to handle Pydantic v2 model_dump() including keys with None values
    - Add unit test for mixed function_result and function_approval_response
      in the same message to TestExtractResponsesFromMessages
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>