Commit Graph

277 Commits

  • Python: Support OpenAI and Gemini allowed_tools tool choice (#5322)
    * Support OpenAI allowed_tools in ToolMode (#5309)
    
    Add allowed_tools field to ToolMode TypedDict, enabling users to restrict
    which tools the model may call via the OpenAI allowed_tools tool_choice
    type. This preserves prompt caching by keeping all tools in the tools list
    while limiting which ones the model can invoke.
    
    - Add allowed_tools: list[str] to ToolMode TypedDict
    - Add validation in validate_tool_mode() (only valid when mode == "auto")
    - Convert to OpenAI API format in _prepare_options()
    - Add tests for validation and API payload generation
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Support OpenAI `allowed_tools` tool choice in Python SDK
    
    Fixes #5309
    
    * Fix #5309: Validate allowed_tools shape and add Chat Completions client support
    
    - validate_tool_mode now checks allowed_tools is a non-string sequence of
      strings and normalizes to list[str], raising ContentError for invalid types
    - Add missing allowed_tools branch in _chat_completion_client._prepare_options
      so allowed_tools is emitted as the OpenAI allowed_tools wire format instead
      of being silently dropped
    - Add tests for invalid allowed_tools types (string, int, mixed), empty list,
      tuple normalization, and Chat Completions client payload generation
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: support allowed_tools with mode 'required' in addition to 'auto'
    
    OpenAI's allowed_tools tool_choice type supports both mode 'auto' and
    'required'. Update validation, client conversion, and tests to allow
    both modes instead of restricting to 'auto' only.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: use Gemini VALIDATED mode for allowed_tools, warn in unsupported providers
    
    - Use FunctionCallingConfigMode.VALIDATED instead of ANY when allowed_tools
      is set with auto mode in Gemini, preserving optional tool-call semantics.
    - Handle allowed_tools in required mode with required_function_name precedence.
    - Fix allowed_names guard to use identity check (is not None) so empty lists
      are preserved.
    - Bump google-genai minimum to >=1.32.0 (VALIDATED added in that version).
    - Add warnings in Anthropic and Bedrock when allowed_tools is set but not
      supported.
    - Add Gemini unit tests for allowed_tools with auto, required, empty list,
      and required_function_name precedence scenarios.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: Chat Completions API does not support allowed_tools, add integration tests
    
    - Chat Completions API (_chat_completion_client.py) now warns and falls
      back to plain mode when allowed_tools is set, since the /chat/completions
      endpoint does not support the allowed_tools type.
    - Add allowed_tools integration test param to both OpenAIChatClient
      (Responses API) and OpenAIChatCompletionClient parametrized option tests.
    - Update Chat Completions unit tests to reflect the warn-and-fallback
      behavior.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: remove unused walrus operator variable in chat completion client
    
    Remove assigned-but-never-used variable 'allowed' flagged by ruff F841.
    
    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 spans not correctly nested when using streaming (#5552)
    * Fix spans not correctly nested when using streaming
    
    * fix pre commit
    
    * Address comments
  • Python: Feature/hosted dwf (#5531)
    * Fix declarative Workflow.as_agent() by accepting list[Message] in start executor
    
    The declarative start executor (JoinExecutor) only advertised dict and str
    in its input_types, so WorkflowAgent.__init__ rejected it with
    'Workflow's start executor cannot handle list[Message]'.
    
    Add list[Message] to the JoinExecutor handler annotation and add a
    matching branch in DeclarativeActionExecutor._ensure_state_initialized
    that extracts the last user-message text and falls through to the
    string-input initialization path, so =System.LastMessageText works
    end-to-end via as_agent().
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Populate Conversation.messages from list[Message] trigger
    
    When Workflow.as_agent() is invoked with a list[Message], the start executor now populates Conversation.messages / Conversation.history / System.conversations.{id}.messages with prior turns only (excluding the latest user message), and surfaces the latest user message via Inputs.input and System.LastMessage*. This matches InvokeAzureAgent's contract that the messages binding holds prior turns and the executor itself appends the new user input before invoking, avoiding double-append of the trailing user turn while preserving full history (incl. assistant/system/tool roles and multi-modal content) for downstream actions.
    
    * Coerce Enum values when serializing PowerFx symbols
    
    MessageRole and other str-subclass Enums passed isinstance(v, str) and were forwarded to pythonnet unchanged. pythonnet then raised 'MessageRole value cannot be converted to System.String' for every PowerFx primitive when ConditionGroup/Expr eval walked the symbol table containing Conversation.messages. Reduce Enum members to their underlying value before the primitive check so eval sees plain strings/ints.
    
    * Foundry hosting: pass full conversation history to workflow agents
    
    _handle_inner_workflow only forwarded the latest user turn to WorkflowAgent.run, even though _handle_inner_agent already prepends history fetched from Foundry storage to the messages it sends a regular agent. Declarative workflows reset Conversation.messages on every run (state.initialize), so checkpoint replay alone does not give them prior turns - the host has to pass them in, the same way it does for non-workflow agents. Mirror that contract: fetch context.get_history() and pass [*history, *input_messages] to the workflow agent.
    
    * feat(workflows): support combined message + checkpoint_id for multi-turn continuation
    
    Allow Workflow.run(message=..., checkpoint_id=...) so callers can restore
    prior workflow state from a checkpoint AND deliver a new message to the
    start executor in a single call. The existing reset_context logic
    already preserves shared state when checkpoint_id is set, so this gives
    us 'fresh start executor invocation with prior state intact' - exactly
    what hosted multi-turn declarative workflows need.
    
    - _workflow.py: drop the message+checkpoint_id mutual exclusion and
      update _execute_with_message_or_checkpoint to do both (restore then
      execute) when both are provided.
    - _agent.py: in _run_core's checkpoint branch, also forward
      input_messages so WorkflowAgent.run(messages, checkpoint_id=...) works
      end-to-end. Falls back to the legacy 'restore only' behavior when
      messages are absent.
    - _declarative_base.py: detect continuation in _ensure_state_initialized
      by checking whether DECLARATIVE_STATE_KEY already exists in shared
      state; if so, refresh inputs/LastMessage* and append non-user trigger
      messages instead of calling state.initialize() (which would wipe
      Conversation/Local/System).
    - foundry_hosting/_responses.py: collapse the host's two-call pattern
      (restore-only, then fresh run) into a single combined call now that
      the underlying APIs support it.
    - tests: drop the assertion that combined message+checkpoint_id raises.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Pivot: preserve workflow state across run() calls
    
    Replace the prior 'combined message + checkpoint_id in one run()' approach
    with a cleaner default: Workflow.run no longer wipes shared state or runner-
    context messages between calls. Iteration counting and per-run kwargs still
    reset on a fresh-message run; checkpoint and responses runs are continuations
    that preserve everything.
    
    This lets a WorkflowAgent be invoked repeatedly on the same instance and
    maintain multi-turn context (e.g. accumulated Conversation.messages) without
    asking developers to opt in. Hosted-agent multi-turn pattern becomes two
    explicit calls: restore-from-checkpoint (drive to idle), then run-with-message.
    
    Key changes:
    - _workflow.py: drop _state.clear() and reset_for_new_run() from run().
      Reset iteration count and run kwargs on fresh-message runs only.
      Restore 'Cannot provide both message and checkpoint_id' validation.
      Add async guard: fresh-message run with un-drained pending executor
      messages from a prior run is invalid.
    - _runner.py: clear _state before import_state in restore_from_checkpoint
      so restore is authoritative (import_state merges, not replaces).
    - _agent.py: revert checkpoint branch to restore-only (no message forward).
    - _responses.py (foundry_hosting): two-call host pattern - restore checkpoint
      silently, then run with new user input.
    - tests: state-preservation is the new default; rebuild Workflow for clean slate.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CI lint and mypy issues from prior pivot commit
    
    - _workflow.py: collapse nested if (SIM102), drop redundant assignment (RET504)
    - _declarative_base.py: remove unused last_user_msg = tail assignment
      whose Message | None type clashed with the prior Message-typed branch
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review: fix Inputs.input update and checkpoint storage path
    
    - _declarative_base.py: continuation branch was writing 'Inputs.input' via
      state.set, which routes to the Custom namespace and never updates the
      PowerFx-visible Workflow.Inputs.input. Update state_data['Inputs'] in
      place via get_state_data / set_state_data so =Workflow.Inputs.input and
      =inputs.input see the new turn's user text on continuation.
    - _declarative_base.py: refresh docstring to clarify that on a list[Message]
      trigger, Conversation.messages excludes the current user message at the
      start of the turn (agent executors append it before invoking the inner
      agent).
    - _responses.py: when previous_response_id is supplied (no conversation_id),
      the prior checkpoint lives under <storage>/<previous_response_id> but new
      checkpoints must land under <storage>/<current_response_id> for the next
      turn to find them. Hold onto restore_storage from the get_latest lookup
      and pass it to the restore-only run; pass write_storage (current id) to
      the message-delivery run and to checkpoint cleanup.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pyright errors in _declarative_base.py for CI
    
    - Replace state._state.get(...) protected access with new public
      is_initialized() method on DeclarativeWorkflowState (also clearer intent
      for the continuation detection use case).
    - Add narrow pyright ignores for the Any-typed trigger paths that pyright
      cannot fully narrow (the list[Message] isinstance loop and the
      fallback-DefaultTransform branch).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address Copilot review batch: tests + Workflow.reset escape hatch
    
    * Add Workflow.reset() public method as recovery escape hatch when an
      in-flight run aborted (e.g. WorkflowConvergenceException) and the
      workflow is not checkpointed. Update the in-flight messages guard's
      error message to point callers at it.
    
    * Add test_workflow_run_inflight_messages_guard exercising both the
      guard (sync + streaming) and the reset() recovery path.
    * Add test_workflow_reset_rejects_concurrent_runs to lock down the
      in-progress guard on reset.
    
    * Add test_as_agent_continuation_preserves_prior_state covering the
      is_continuation branch in _ensure_state_initialized: stamps a marker
      between calls and asserts it survives, while Inputs.input and
      System.LastMessageText refresh to the new turn.
    
    * Add test_powerfx_safe.py regression tests for the Enum branch in
      _make_powerfx_safe (str-subclass, int-subclass, plain Enum, and
      Enums nested in dict/list).
    
    * Drop redundant @pytest.mark.asyncio on
      test_as_agent_round_trip_with_last_message_text (asyncio_mode='auto').
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Skip restore-only pre-pass when checkpoint has pending request_info
    
    Address Copilot review on _responses.py: the restore-only checkpoint
    replay populates self._agent.pending_requests for any request_info
    events captured in the checkpoint. The follow-up run(input_messages)
    call would then route through WorkflowAgent._process_pending_requests,
    which expects function-response content and rejects plain text input
    as 'unexpected content while awaiting request info responses'.
    
    Workflows resumed from a checkpoint that was idle-with-pending-requests
    would therefore fail every subsequent plain-text user turn. Inspect the
    loaded checkpoint and skip the pre-pass when its
    pending_request_info_events dict is non-empty. Workflows that don't use
    request_info (the current sample set) are unaffected; workflows that do
    will fall through to a fresh-message run rather than silently corrupting
    the routing state.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Loosen azure-ai-agentserver-* pins to major version
    
    The exact-version pins on azure-ai-agentserver-{core,responses,invocations}
    forced foundry-hosting consumers to upgrade in lockstep with every beta
    bump from upstream. Switch to '>=current,<next-major' so we pick up patch
    and feature updates within the same major series without a coordinated
    release.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Drop Workflow.reset(); checkpointing is the recovery path
    
    The in-flight-messages guard prevented silent misbehavior, but the
    companion Workflow.reset() escape hatch only cleared _messages while
    leaving iteration count, executor-local state, and shared State
    mutations in an indeterminate condition after a mid-run failure. That
    gave a false sense of recovery.
    
    Recovery from a mid-run failure is supported only via checkpoint
    restoration. Keep the guard and reframe its error message accordingly;
    remove reset() and its tests.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address Tao's review on PR 5531
    
    - Rename Workflow._run_workflow_with_tracing parameter
      is_fresh_message_run -> is_continuation (default False, inverted).
      Fresh-message turns reset per-run accounting; continuations
      (checkpoint restores, responses replays) preserve it.
    - Simplify the in-flight-messages guard: _validate_run_params already
      enforces that 'message' is mutually exclusive with 'checkpoint_id'
      and 'responses', so the additional checks were dead code.
    - foundry_hosting _responses: move the restore-only pre-pass above
      emit_created/emit_in_progress; restore is preparation, not run
      progress. Drop the skip-restore gate (state preservation requires
      unconditional restore) and instead clear agent.pending_requests
      after the restore-only call. Collapse over-conditioned check.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Don't clear pending_requests after restore-only pre-pass
    
    Pending requests in the restored checkpoint represent genuinely
    outstanding HITL requests. The next user input may carry function
    responses (Responses API `function_call_output` items become
    FunctionResultContent / FunctionApprovalResponseContent), which
    `WorkflowAgent._process_pending_requests` correctly extracts and
    matches against the populated `pending_requests`. Clearing them
    after restore would silently drop that state and force the next turn
    to be treated as a fresh input even when the caller is responding to
    the outstanding requests.
    
    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: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
  • Python: [BREAKING] Standardize orchestration terminal outputs as AgentResponse (#5301)
    * Fix orchestration outputs so as_agent() returns the final answer only. Align other orchestration outputs
    
    * Fix orchestration output issues from review comments
    
    1. Sample cleanup: Remove commented-out FoundryChatClient block and update
       prerequisites to reference OPENAI_CHAT_MODEL_ID instead of FOUNDRY_* vars.
    
    2. Sequential approval output: Change _EndWithConversation.end_with_agent_executor_response
       from a no-op sink to yield response.agent_response. When the last participant is
       AgentApprovalExecutor (via with_request_info), _EndWithConversation is the output
       executor so the yield produces the terminal answer. When the last participant is a
       regular AgentExecutor, _EndWithConversation is not in output_executors so the yield
       is silently filtered out.
    
    3. Forward data events through WorkflowExecutor: _process_workflow_result now also
       forwards 'data' events from sub-workflows so that emit_intermediate_data=True on
       AgentExecutor works correctly when wrapped in AgentApprovalExecutor.
    
    4. Concurrent docstring: Update _AggregateAgentConversations docstring to say
       'deterministic participant order' instead of 'completion order'.
    
    5. Add test_concurrent_intermediate_outputs_emits_data_events verifying that
       ConcurrentBuilder(intermediate_outputs=True) emits per-participant data events
       alongside the single aggregated output event.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add tests for sequential workflow with_request_info and intermediate_outputs (#5301)
    
    Address PR review comments 2, 3, and 5:
    
    - Add test_sequential_request_info_last_participant_emits_output:
      Verifies that when the last participant is wrapped via with_request_info()
      (AgentApprovalExecutor), the workflow still emits a terminal output after
      approval, exercising the _EndWithConversation.end_with_agent_executor_response
      fallback path.
    
    - Add test_sequential_request_info_with_intermediate_outputs_emits_data_events:
      Verifies that emit_intermediate_data=True works correctly through
      AgentApprovalExecutor wrapping—WorkflowExecutor._process_result already
      forwards data events from sub-workflows, so intermediate agent responses
      surface as data events in the parent workflow.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pyright type errors from AgentResponse output refactor (#5301)
    
    Update cast() calls in _group_chat.py and _magentic.py to use
    WorkflowContext[Never, AgentResponse] instead of the old
    WorkflowContext[Never, list[Message]], matching the updated method
    signatures in _base_group_chat_orchestrator.py.
    
    Fix _sequential.py _EndWithConversation.end_with_agent_executor_response
    to declare WorkflowContext[Any, AgentResponse] so yield_output accepts
    AgentResponse[None].
    
    Fix _workflow_executor.py data event forwarding to handle nullable
    executor_id.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pyright reportUnknownVariableType in _agent.py (#5301)
    
    Extract event.data into a typed local variable before the isinstance
    check to avoid pyright narrowing it to AgentResponse[Unknown].
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pyright reportMissingImports for orjson in file history samples (#5301)
    
    Add pyright: ignore[reportMissingImports] to orjson imports that are
    already guarded by try/except ImportError, matching the existing pattern
    used elsewhere in the samples.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #5301: review comment fixes
    
    * Address review feedback for #5301: review comment fixes
    
    * Revert sequential_workflow_as_agent sample to FoundryChatClient
    
    Reverts the mistaken switch from FoundryChatClient to OpenAIChatClient
    in the sequential workflow as agent sample.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address ultrareview feedback: emit_data_events rename + WorkflowAgent reasoning conversion
    
    Layered on top of the prior review-feedback work in this branch.
    
    Renames:
    - AgentExecutor.emit_intermediate_data -> emit_data_events (mechanical
      rename; orchestration semantics live at the orchestration layer, not
      the general-purpose executor). Forwarded through MagenticAgentExecutor,
      AgentApprovalExecutor, and all orchestration call sites.
    - HandoffAgentExecutor._check_terminate_and_yield -> _should_terminate
      (pure predicate; no longer yields anything). HandoffBuilder docstring
      rewritten to describe the new per-agent AgentResponse output contract.
    
    WorkflowAgent reasoning-content conversion:
    - Add _rewrite_text_to_reasoning(contents) and _msg_as_reasoning(msg)
      helpers; the as_agent() path now reframes text content from data events
      as text_reasoning Content blocks before merging into the AgentResponse.
    - Consumers iterate msg.contents and branch on content.type — same path
      they already use for Claude thinking and OpenAI reasoning. No new
      field on Message/AgentResponse/WorkflowEvent.
    - Streaming branch constructs fresh AgentResponseUpdate instances instead
      of mutating shared payloads (regression test added).
    - Helper _msg_maybe_reasoning consolidates the conditional rewrite at
      three call sites in the non-streaming conversion.
    
    Tests:
    - TestWorkflowAgentReasoningHelpers + TestWorkflowAgentDataEventReasoningConversion
      add 9 new tests covering helpers, non-streaming, streaming, mixed content,
      already-reasoning passthrough, and mutation-safety regression.
    - Updated test_sequential_as_agent_with_intermediate_outputs_includes_chain
      to assert text_reasoning content for intermediate agents.
    
    * Fix pyright: widen event.data to Any to avoid partial-unknown narrowing
    
    The streaming conversion path narrowed event.data via isinstance against
    generic AgentResponse, producing AgentResponse[Unknown] and tripping
    reportUnknownVariableType/reportUnknownMemberType. Binding data: Any
    before the check keeps runtime behavior identical while restoring a fully
    known type for downstream access.
    
    * Clean up design
    
    * Scope to agent output semantics only
    
    * yield AgentResponseUpdate streaming, AgentResponse non-streaming
    
    * Fix mypy/pyright: widen cast types at GroupChat callsites
    
    Eight callsites in _group_chat.py still cast to WorkflowContext[Never,
    AgentResponse] but the base orchestrator methods now accept the wider
    WorkflowContext[Never, AgentResponse | AgentResponseUpdate] (mode-aware
    yields). W_OutT is invariant, so the narrower cast is not assignable.
    Magentic was widened in the same commit; this catches the GroupChat
    callsites that were missed.
    
    * Python: skip flaky Foundry / Foundry Hosting integration tests (#5553)
    
    These two integration tests have been failing in the merge queue across
    multiple unrelated PRs (5301, 5531). Both are marked `@pytest.mark.flaky`
    with 3 retries, but all attempts fail back-to-back. Skipping both with a
    reason pointing to #5553 so they can be fixed properly without continuing
    to block unrelated merges.
    
    - packages/foundry_hosting/tests/test_responses_int.py::TestOptions::test_temperature_and_max_tokens
    - packages/foundry/tests/foundry/test_foundry_embedding_client.py::TestFoundryEmbeddingIntegration::test_text_embedding_live
    
    Also includes a one-line uv.lock specifier-ordering normalization
    auto-applied by the poe-check pre-commit hook.
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add requirements.txt and .env.example to the a2a/ sample for pip-based setup (#5510)
    * Add requirements.txt and .env.example to a2a sample
    
    Beginners following the a2a/ sample had no pip-based install path:
    the directory lacked requirements.txt and .env.example, unlike every
    other 04-hosting/ sample.
    
    - Add requirements.txt with editable local package paths matching the
      pattern used in azure_functions/ and similar hosting samples
    - Add .env.example documenting FOUNDRY_PROJECT_ENDPOINT, FOUNDRY_MODEL,
      and A2A_AGENT_HOST
    - Update README Quick Start to cover both pip (.venv) and uv workflows
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Add `requirements.txt` and `.env.example` to the `a2a/` sample for pip-based setup
    
    Fixes #5395
    
    * fix(a2a-sample): address PR review feedback for issue #5395
    
    - Remove 'from repo root' wording from Option B uv heading in README
      to avoid contradicting the 'run from this directory' instruction
    - Fix A2A_AGENT_HOST default in .env.example from 5001 to 5000 to match
      function-tools flow; add clarifying comments about port usage
    - Add note for pip users explaining they can replace 'uv run python'
      with 'python' once the virtual environment is activated
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #5395: Python: [Samples][Python] a2a/ sample missing requirements.txt — beginners cannot install dependencies
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: fix: prevent inner_exception from being lost in AgentFrameworkException (#5167)
    * fix: prevent inner_exception from being lost in AgentFrameworkException
    
    The __init__ method unconditionally called super().__init__() after
    the conditional call with inner_exception, effectively overwriting the
    exception args and losing the inner_exception reference.
    
    Add else branch so super().__init__() is only called once with the
    correct arguments.
    
    Fixes #5155
    
    Signed-off-by: bahtya <bahtyar153@qq.com>
    
    * test: add explicit tests for AgentFrameworkException inner_exception handling
    
    - test_exception_with_inner_exception: verifies args include inner exception
    - test_exception_without_inner_exception: verifies args only contain message
    - test_exception_inner_exception_none_explicit: verifies explicit None
    
    Covers both branches of the if/else in __init__.
    
    * fix: export AgentFrameworkException from package
    
    Bahtya
    
    ---------
    
    Signed-off-by: bahtya <bahtyar153@qq.com>
  • Python: (core): Add functional workflow API (#4238)
    * Add functional workflow api
    
    * cleanup
    
    * More cleanup
    
    * address copilot feedback
    
    * Address PR feedbacK
    
    * updates
    
    * PR feedback
    
    * Address review comments on functional workflow samples
    
    - Swap 05/06 get-started samples: agent workflow first (motivates
      why workflows exist), simple text workflow second
    - Rename text_pipeline → text_workflow, poem_pipeline → poem_workflow
    - Add @step to agent workflow sample (05) to demonstrate caching
    - Switch agent samples to AzureOpenAIResponsesClient with Foundry
    - Remove .as_agent() from agent_integration.py to focus on the key
      difference between inline agent calls vs @step-cached calls
    - Add commented-out Agent.run example in hitl_review.py
    - Add clarifying comment in _functional.py that event streaming is
      buffered (not true per-token streaming)
    - Add naive_group_chat.py functional sample: round-robin group chat
      as a plain Python loop
    - Update READMEs to reflect new file names and group chat sample
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pyright type errors
    
    * Address PR review comments on functional workflow API
    
    1. Allow request_info inside @step: Auto-inject RunContext into step
       functions that declare a RunContext parameter (by type or name 'ctx'),
       and expose get_run_context() for programmatic access.
    
    2. Handle None responses: Log a warning when a response value is None,
       and document the behavior in request_info docstring.
    
    3. Add executor_bypassed event type: Replace executor_invoked +
       executor_completed with a single executor_bypassed event when a step
       replays from cache, making cached vs live execution explicit.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add regression tests for PR review comments on functional workflow API
    
    The three review comments (request_info in @step, None response handling,
    executor_bypassed event type) were already addressed in 7da7db4e. This
    commit adds cross-cutting regression tests that exercise the interactions
    between these features:
    
    - HITL in step with caching: preceding step bypassed on resume
    - Full checkpoint lifecycle with HITL step (interrupt -> resume -> restore)
    - None response inside step-level request_info logs warning
    - WorkflowInterrupted from step does not emit executor_failed
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR #4238 review comments on functional workflow API
    
    Comment 1 (request_info in @step): Already supported. Added comment in
    StepWrapper.__call__ explaining why WorkflowInterrupted (BaseException)
    safely bypasses the except Exception handler.
    
    Comment 2 (None response): Added docstring to _get_response clarifying
    the (found, value) return tuple semantics and None handling.
    
    Comment 3 (bypass event type): executor_bypassed is already a dedicated
    event type in WorkflowEventType. Updated comment at the bypass site to
    make the deliberate event type choice explicit.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add experimental API warnings to functional workflow module
    
    Mark all public classes and decorators (workflow, step, RunContext,
    FunctionalWorkflow, StepWrapper, FunctionalWorkflowAgent) as
    experimental and subject to change or removal.
    
    * Address PR #4238 review comments from @eavanvalkenburg
    
    - RunContext docstring leads with purpose (opt-in handle for HITL,
      custom events, state) so readers importing it from the public surface
      understand its role before the mechanics (#2993513452).
    - Rename `06_first_functional_workflow.py` to
      `06_functional_workflow_basics.py`; the previous filename was
      confusing since it followed `05_functional_workflow_with_agents.py`
      (#2993531979).
    - Simplify `05_functional_workflow_with_agents.py` to call agents
      directly without a @step wrapper; the step-vs-no-step contrast lives
      in `03-workflows/functional/agent_integration.py`, keeping the
      get-started sample minimal (#2993525532).
    - Switch functional samples to `FoundryChatClient` for consistency with
      the rest of 01-get-started and 03-workflows (follow-up on #2876988570).
    - Use walrus in `hitl_review.py` final-state assertion (#2993572182).
    - Add expected-output block to `basic_streaming_pipeline.py` (#2993557609).
    - Clarify in `parallel_pipeline.py` that `@step` composes with
      `asyncio.gather` (#2993597282).
    - `naive_group_chat.py` threads `list[Message]` between turns instead
      of stringifying the transcript, preserving role/authorship (#2993583231).
    
    Drive-by: pre-commit hook sorts an unrelated import block in
    `samples/04-hosting/foundry-hosted-agents/responses/02_local_tools/main.py`.
    
    * Fix 10 functional-workflow API bugs from /ultrareview pass
    
    - bug_001: `ctx.request_info()` without an explicit `request_id` now derives
      a deterministic `auto::<index>` id from the call-counter, so HITL resume
      works correctly on the documented default path.  A uuid was regenerated on
      every replay, making resume impossible.
    
    - bug_002: `StepWrapper.__call__` no longer deepcopies arguments on the
      cache-hit replay branch.  The copy is only performed on the live-execution
      path (for the event log) and falls back to the original mapping if deepcopy
      fails, so steps whose args aren't deepcopyable (locks, sockets, sessions)
      can still resume from checkpoint.
    
    - bug_007: `_set_responses` now prunes each resolved `request_id` from
      `_pending_requests`, and the cache-hit branch in `request_info` does the
      same.  Previously, answered requests were re-serialized into every
      subsequent checkpoint and the final checkpoint falsely claimed pending
      requests even after the workflow completed.
    
    - bug_008: `_compute_signature_hash` now mixes the function's `co_code` and
      `co_names` into the checkpoint signature, so changes to the workflow body
      invalidate older checkpoints even when steps are accessed via module /
      class attributes (which `_discover_step_names` can't see statically).
      `RunContext._record_observed_step` records observed step names for
      diagnostics.
    
    - bug_010: `FunctionalWorkflow.run()` docstring corrected — says "at least
      one of message/responses/checkpoint_id" and explicitly notes `responses`
      may be combined with `checkpoint_id` (the validator already allowed this).
    
    - bug_013: `FunctionalWorkflowAgent` now surfaces `request_info` events as
      `FunctionApprovalRequestContent` items (mirroring graph `WorkflowAgent`),
      threads `responses=` and `checkpoint_id=` through to the underlying
      workflow, and exposes `pending_requests`.  Previously `.as_agent()`
      returned empty `AgentResponse` for HITL workflows — effectively unusable.
    
    - bug_014: `FunctionalWorkflow` now clears `_last_message`,
      `_last_step_cache`, and `_last_pending_request_ids` on clean completion.
      `run()` validates that `responses=` keys intersect the currently-pending
      request set (or raises with a clear error) instead of silently replaying
      against stale singleton state from a prior run.
    
    - bug_015: `FunctionalWorkflow.as_agent` signature now matches graph
      `Workflow.as_agent`: accepts `name`, `description`, `context_providers`,
      and `**kwargs`.  `FunctionalWorkflowAgent` stores the overrides.
    
    - bug_017: `RunContext.set_state` raises `ValueError` for underscore-
      prefixed keys (the framework's `_step_cache` / `_original_message` keys
      would silently clobber user state on checkpoint save and user
      underscore-prefixed state was dropped on restore).  Docstring documents
      the reserved prefix.
    
    - merged_bug_003: Workflow function arity is validated at decoration time.
      Multiple non-ctx parameters raise `ValueError` immediately (previously
      every arg past the first was silently dropped at call time).  Passing a
      non-None `message` to a ctx-only workflow raises `ValueError` instead of
      silently discarding the message.
    
    Test coverage: +18 regression tests covering every fix.  Full workflow
    suite now 766 passed, 1 skipped, 2 xfailed; full core suite 2338 passed.
    
    * Deslop functional.py fix commit
    
    - Remove dead instrumentation added in the prior commit that was never
      consumed: `RunContext._observed_step_names`,
      `RunContext._record_observed_step`, `FunctionalWorkflow._runtime_step_names`,
      and `FunctionalWorkflowAgent._extra_kwargs`.  The signature hash relies on
      `co_code` alone, which covers the attribute-access case without the
      collection-scaffolding.
    - Trim over-explanatory comments that restated what the code does or what
      it no longer does.  Keep only the comments that answer "why" for the
      non-obvious bits (deterministic id contract, defensive deepcopy, stale
      replay guard).
    - Compress the `_compute_signature_hash` and FunctionalWorkflow `__init__`
      block docstrings without losing the user-facing reasoning.
    
    Net -49 lines.  Regression lock preserved (766 passed, 1 skipped, 2 xfailed).
    
    * Fix functional workflow review feedback
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Copilot <copilot@github.com>
  • Python: Fix user agent prefix (#5455)
    * Fix hosting user agent missing
    
    * Fix other providers
    
    * Add more tests
    
    * comments
    
    * Fix tests
  • Python: Hyperlight: thread-confine sandbox, skip parsing on host callbacks, schema/tool cleanup (#5424)
    * improved parsing of tool call results and tweaks
    
    * Address PR review: skip_parsing flag, broader registry close, comment fix
    
    - FunctionTool.invoke now takes a boolean skip_parsing flag instead of the
      SKIP_PARSING sentinel; the sentinel is still accepted as result_parser at
      construction time to opt out of parsing for every call. The two paths are
      equivalent.
    - _SandboxRegistry.close now invokes any sandbox close/shutdown hook on the
      entry's own worker thread (PyO3 unsendable), then shuts the worker down,
      then cleans up the per-entry temporary directories.
    - Clarified the _SandboxWorker.shutdown comment to describe the actual
      ThreadPoolExecutor.shutdown(wait=False, cancel_futures=False) semantics.
    - Hyperlight host callback uses skip_parsing=True (the new flag).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Drop redundant 'is not SKIP_PARSING' guard that mypy 1.x flags
    
    After callable(configured_parser) the sentinel is already excluded; the extra
    identity check tripped mypy's non-overlapping identity warning.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fixed sandbox working on copy of tool
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add second approval-required tool (set_stop_loss) to concurrent_builder_tool_approval sample (#4875)
    * Add set_stop_loss tool to concurrent_builder_tool_approval sample
    
    Add a second approval-gated tool (set_stop_loss) to the concurrent workflow
    tool approval sample to demonstrate handling approval requests for different
    tools in the same concurrent workflow.
    
    Changes:
    - Add set_stop_loss(symbol, stop_price) with approval_mode='always_require'
    - Include new tool in both agents' tool lists
    - Update agent instructions and prompt to encourage stop-loss usage
    - Update docstring to reflect two approval-gated tools
    - Update sample output to show mixed approval requests
    
    Fixes #4874
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Print tool name and arguments in concurrent sample's process_event_stream (#4874)
    
    Align process_event_stream in concurrent_builder_tool_approval.py to print
    the tool name and arguments when collecting approval requests, matching the
    sample output comment and the sequential_builder_tool_approval.py pattern.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add None-guard for function_call access in tool approval sample (#4874)
    
    Add explicit None-checks before accessing function_call.name and
    function_call.arguments in concurrent_builder_tool_approval.py. The
    function_call field is typed Content | None, so direct attribute access
    without a guard could raise AttributeError and required type: ignore
    comments. The None-guard is consistent with the pattern used in
    _agent_run.py and removes the suppression comments.
    
    Also add a regression test verifying that function_call defaults to None
    and that the None-guard pattern is safe.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply same function_call None-guard to sibling tool-approval samples (#4874)
    
    Apply the same fix to sequential_builder_tool_approval.py and
    group_chat_builder_tool_approval.py, which had the identical pattern
    of accessing function_call.name/arguments without a None-guard.
    
    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: Foundry hosted agent V2 (#5379)
    * Python: Wrapper + Samples 1st (#5177)
    
    * Experiment
    
    * Update dependency and add non streaming
    
    * Add more samples
    
    * Rename samples
    
    * Add invocations
    
    * Comments 1
    
    * Comments 2
    
    * Comments 3
    
    * Improve README
    
    * Add local shell sample
    
    * WIP: Add eval and memory samples
    
    * Update user agent prefix
    
    * Update user agent prefix doc
    
    * Update dependency (#5215)
    
    * Add tests and more content types (#5235)
    
    * Add tests
    
    * fix tests and sample
    
    * Fix formatting
    
    * Remove function approval contents
    
    * Python: Refine samples and upgrade packages (#5261)
    
    * Refine samples and upgrade pacakges
    
    * Upgrade to a new package that fixes a bug
    
    * Update model env var
    
    * Move samples (#5281)
    
    * Python: Upgrade agentserver packages (#5284)
    
    * Upgrade agentserver packages
    
    * Fix new types
    
    * Python: Add special handling for workflows (#5298)
    
    * Add special handling for workflows
    
    * Address comments
    
    * Improve samples (#5372)
    
    * Python: Add more types (#5378)
    
    * Add more type supports
    
    * Upgrade packages
    
    * Remove TODOs in README
    
    * Fix README
    
    * Comments and mypy
    
    * User agent scoped
    
    * Fix README
    
    * Fix pre commit
    
    * Fix pre commit 2
    
    * Fix pre commit 3
    
    * Fix pre commit 4
    
    * Fix pre commit 5
    
    * Fix pre commit 6
    
    * Add azure-monitor-opentelemetry to dev deps
    
    Fixes Samples & Markdown CI failure. The PR's new transitive dep on
    azure-monitor-opentelemetry-exporter (via azure-ai-agentserver-core) makes
    pyright resolve the azure.monitor.opentelemetry namespace, flipping the
    check_md_code_blocks diagnostic for `configure_azure_monitor` from
    reportMissingImports (filtered) to reportAttributeAccessIssue (not filtered).
    Installing the umbrella azure-monitor-opentelemetry package in dev makes
    pyright resolve the symbol correctly, matching the install guidance the
    observability README already gives users.
    
    ---------
    
    Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
  • Python: Add support for Foundry Toolboxes (#5346)
    * Add support for the Foundry Toolbox in MAF
    
    Introduces a Foundry Toolbox integration: FoundryChatClient gains a
    get_toolbox() helper plus select_toolbox_tools(), normalize_tools in
    the core package flattens tool-collection wrappers (ToolboxVersionObject
    and generic iterables, while leaving Pydantic BaseModel instances
    alone), and the new agent_framework.foundry namespace re-exports the
    toolbox helpers. Ships with unit tests, a sample, and a design doc.
    
    azure-ai-projects is pinned to the public >=2.0.0,<3.0 range and the
    lockfile resolves from public PyPI. The toolbox test module skips when
    Toolbox* types are unavailable so CI stays green until the public 2.1.0
    SDK lands. OMC tooling directories (.omc/, .omx/) are gitignored.
    
    * Update to latest azure ai projects package
    
    * Improve sample
    
    * Rename ADR to 0025
    
    * Update ADR
    
    * Apply suggestion from @alliscode
    
    Co-authored-by: Ben Thomas <ben.thomas@microsoft.com>
    
    * Improve samples
    
    * Update test
    
    ---------
    
    Co-authored-by: Ben Thomas <ben.thomas@microsoft.com>
  • Python: Feat: Add finish_reason support to AgentResponse and AgentResponseUpdate (#5211)
    * feat: add finish_reason support to AgentResponse and AgentResponseUpdate
    
    Add finish_reason field to AgentResponse and AgentResponseUpdate classes,
    propagate it through _process_update() and map_chat_to_agent_update(),
    and add comprehensive unit tests.
    
    Fixes #4622
    
    * feat: add finish_reason to AgentResponse and AgentResponseUpdate
    
    * style: add copyright header to test_finish_reason.py
    
    * docs: add finish_reason to AgentResponse and AgentResponseUpdate docstrings
    
    * refactor: move finish_reason tests into test_types.py per review feedback
    
    Move all finish_reason test cases from the separate test_finish_reason.py
    file into test_types.py as requested by eavanvalkenburg. Tests are placed
    in a new '# region finish_reason' section at the end of the file.
    
    * fix: use model instead of model_id in _process_update
    
    Address PR review feedback from @eavanvalkenburg — ChatResponse and
    ChatResponseUpdate both use 'model', not 'model_id'.
    
    * fix: resolve SIM102 lint error in _process_update
    
    Combine nested if statements for AgentResponse finish_reason check
    to satisfy ruff SIM102 rule, with line wrapping to stay under 120 chars.
    
    * fix: resolve pyright reportArgumentType in map_chat_to_agent_update
    
    Add type: ignore[arg-type] for FinishReason NewType widening when
    passing ChatResponseUpdate.finish_reason to AgentResponseUpdate.
    Matches existing patterns in the codebase (40+ similar ignores).
  • Python: Fix Gemini client support for Gemini API and Vertex AI (#5258)
    * Add Gemini and Vertex AI client support
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address Gemini PR review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * removed sample run readme part
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
  • Add AgentExecutorResponse.with_text() to preserve conversation history through custom executors (#5255)
    Fixes #5246
    
    When a custom @executor transforms agent output and sends a plain str,
    the downstream AgentExecutor.from_str handler loses the full conversation
    context. This adds a with_text() helper that creates a new
    AgentExecutorResponse with replaced text while preserving the prior
    conversation chain, so AgentExecutor.from_response is invoked instead.
    
    - Add with_text(text) method to AgentExecutorResponse dataclass
    - Add 3 regression tests in test_full_conversation.py
    
    Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
  • Python: Add OpenAI types to default checkpoint encoding allow list (#5297)
    * Add OpenAI types to default checkpoint encoding allow list
    
    * Address comments
  • Python: Add context_providers and description to workflow.as_agent() (#4651)
    * Add context_providers and description to `workflow.as_agent()`
    
    * Add default workflow name and description
    
    * Positional
    
    * Move import
    
    ---------
    
    Co-authored-by: Tao Chen <taochen@microsoft.com>
    Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
  • Python: add experimental file history provider (#5248)
    * add experimental file history provider
    
    * Improve file history provider writes
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * typo
    
    * cleanup
    
    * cleanup
    
    * fix in readme
    
    * added security messages
    
    * Refine file history provider locking
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * added additional sample
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Move InMemory history provider injection to the first invocation (#5236)
    * Move InMemory history provider injection to the first invocation
    
    * Add tests
  • Python: skill name validation improvements (#4530)
    * Initial plan
    
    * Port .NET validation improvements to Python skills: reject consecutive hyphens and enforce directory name match
    
    Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>
    
    * Fix E501 lint error: split long error message string in _validate_skill_metadata
    
    Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>
  • Python: Restrict persisted checkpoint deserialization by default (#4941)
    * Harden Python checkpoint persistence defaults
    
    Add RestrictedUnpickler to _checkpoint_encoding.py that limits which
    types may be instantiated during pickle deserialization.  By default
    FileCheckpointStorage now uses the restricted unpickler, allowing only:
    
    - Built-in Python value types (primitives, datetime, uuid, decimal,
      collections, etc.)
    - All agent_framework.* internal types
    - Additional types specified via the new allowed_checkpoint_types
      parameter on FileCheckpointStorage
    
    This narrows the default type surface area for persisted checkpoints
    while keeping framework-owned scenarios working without extra
    configuration.  Developers can extend the allowed set by passing
    "module:qualname" strings to allowed_checkpoint_types.
    
    The decode_checkpoint_value function retains backward-compatible
    unrestricted behavior when called without the new allowed_types kwarg.
    
    Fixes #4894
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: resolve mypy no-any-return error in checkpoint encoding
    
    Add explicit type annotation for super().find_class() return value
    to satisfy mypy's no-any-return check.
    
    Fixes #4894
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Simplify find_class return in _RestrictedUnpickler (#4894)
    
    Remove unnecessary intermediate variable and apply # noqa: S301 # nosec
    directly on the super().find_class() call, matching the established
    pattern used on the pickle.loads() call in the same file.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4894: Python: Harden Python checkpoint persistence defaults
    
    * Restore # noqa: S301 on line 102 of _checkpoint_encoding.py (#4894)
    
    The review feedback correctly identified that removing the # noqa: S301
    suppression from the find_class return statement would cause a ruff S301
    lint failure, since the project enables bandit ("S") rules. This
    restores consistency with lines 82 and 246 in the same file.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4894: Python: Harden Python checkpoint persistence defaults
    
    * Address PR review comments on checkpoint encoding (#4894)
    
    - Move module docstring to proper position after __future__ import
    - Fix find_class return type annotation to type[Any]
    - Add missing # noqa: S301 pragma on find_class return
    - Improve error message to reference both allowed_types param and
      FileCheckpointStorage.allowed_checkpoint_types
    - Add -> None return annotation to FileCheckpointStorage.__init__
    - Replace tempfile.mktemp with TemporaryDirectory in test
    - Replace contextlib.suppress with pytest.raises for precise assertion
    - Remove unused contextlib import
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR #4941 review comments: fix docstring position and return type
    
    - Move module docstring before 'from __future__' import so it populates
      __doc__ (comment #4)
    - Change find_class return annotation from type[Any] to type to avoid
      misleading callers about non-type returns like copyreg._reconstructor
      (comment #2)
    
    Comments #1, #3, #5, #6, #7, #8 were already addressed in the current code.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4894: review comment fixes
    
    * fix: use pickle.UnpicklingError in RestrictedUnpickler and improve docstring (#4894)
    
    - Change _RestrictedUnpickler.find_class to raise pickle.UnpicklingError
      instead of WorkflowCheckpointException, since it is pickle-level concern
      that gets wrapped by the caller in _base64_to_unpickle.
    - Remove now-unnecessary WorkflowCheckpointException re-raise in
      _base64_to_unpickle (pickle.UnpicklingError is caught by the generic
      except Exception handler and wrapped).
    - Expand decode_checkpoint_value docstring to show a concrete example of
      the module:qualname format with a user-defined class.
    - Add regression test verifying find_class raises pickle.UnpicklingError.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: address PR #4941 review comments for checkpoint encoding
    
    - Comment 1 (line 103): Already resolved in prior commit — _RestrictedUnpickler
      now raises pickle.UnpicklingError instead of WorkflowCheckpointException.
    
    - Comment 2 (line 140): Add concrete usage examples to decode_checkpoint_value
      docstring showing both direct allowed_types usage and FileCheckpointStorage
      allowed_checkpoint_types usage. Rename 'SafeState' to 'MyState' across all
      docstrings for consistency, making it clear this is a user-defined class name.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: replace deprecated 'builtin' repo with pre-commit-hooks in pre-commit config
    
    pre-commit 4.x no longer supports 'repo: builtin'. Merge those hooks into
    the existing pre-commit-hooks repo entry.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * style: apply pyupgrade formatting to docstring example
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: resolve pre-commit hook paths for monorepo git root
    
    The poe-check and bandit hooks referenced paths relative to python/
    but pre-commit runs hooks from the git root (monorepo root). Fix
    poe-check entry to cd into python/ first, and update bandit config
    path to python/pyproject.toml.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pre-commit config paths for prek --cd python execution
    
    Revert bandit config path from 'python/pyproject.toml' to 'pyproject.toml'
    and poe-check entry from explicit 'cd python' wrapper to direct invocation,
    since prek --cd python already sets the working directory to python/.
    
    Also apply ruff formatting fixes to cosmos checkpoint storage files.
    
    Fixes #4894
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: add builtins:getattr to checkpoint deserialization allowlist
    
    Pickle uses builtins:getattr to reconstruct enum members (e.g.,
    WorkflowMessage.type which is a MessageType enum). Without it in the
    allowlist, checkpoint roundtrip tests fail with
    WorkflowCheckpointException.
    
    Fixes #4894
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4894: review comment fixes
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix response_format crash on background polling with empty text (#5146)
    * Guard against empty text in _parse_structured_response_value (#5145)
    
    When using response_format with background=True (Responses API), polling
    an in-progress response produces empty text. _parse_structured_response_value
    unconditionally passed this to model_validate_json/json.loads, causing
    ValidationError or JSONDecodeError.
    
    Add an early return of None when text is empty, matching the existing
    guard for response_format=None. This allows .value to safely return None
    for in-progress background responses.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Fix `response_format` crash on background polling with empty text
    
    Fixes #5145
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Raise clear handler registration error for unresolved TypeVar annotations (#4944)
    * Raise clear handler registration error for unresolved TypeVar (#4943)
    
    Detect unresolved TypeVar in message parameter annotations during handler
    registration in both _validate_handler_signature (Executor) and
    _validate_function_signature (FunctionExecutor). Raises a ValueError with
    an actionable message recommending @handler(input=..., output=...) or
    @executor(input=..., output=...) instead of letting TypeVar leak through
    to a confusing TypeCompatibilityError during workflow edge validation.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4943: reorder checks and harden function executor
    
    - Move TypeVar check before validate_workflow_context_annotation in
      _executor.py so users see the more actionable error first
    - Wrap get_type_hints in try/except in _function_executor.py matching
      the defensive pattern in _executor.py
    - Repurpose duplicate test to cover bounded TypeVar rejection
    - Add test_function_executor_allows_concrete_types for test symmetry
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Narrow get_type_hints except clause and add missing tests (#4943)
    
    - Narrow `except Exception` to `except (NameError, AttributeError, RecursionError)`
      in both _executor.py and _function_executor.py so unexpected failures in
      get_type_hints are not silently swallowed.
    - Add test_handler_unresolvable_annotation_raises to test_function_executor_future.py
      exercising the except branch of get_type_hints in the function executor path.
    - Add test_function_executor_rejects_bounded_typevar_in_message_annotation to
      test_function_executor.py for parity with the Executor bounded TypeVar test.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add error ordering test for TypeVar vs WorkflowContext priority (#4943)
    
    Add test_handler_typevar_error_takes_priority_over_context_error to verify
    that when a handler has both a TypeVar message and an unannotated ctx, the
    TypeVar error is raised first (the more actionable issue).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Fix image content serialization sending null file_id to Foundry API
    
    Omit file_id from input_image dict when not present instead of including
    it as null, which Azure AI Foundry's stricter schema validation rejects.
    
    * Python: Fix Foundry API rejecting rich content in function_call_output
    
    Azure AI Foundry does not support list-format output in function_call_output
    items. Add SUPPORTS_RICH_FUNCTION_OUTPUT flag (default True) to
    RawOpenAIChatClient, set to False in RawFoundryChatClient so Foundry
    falls back to string output for tool results with images/files.
    
    Also omit file_id from input_image dicts when not set, since Foundry
    rejects explicit nulls.
    
    * Python: Surface rich tool content as user message when Foundry lacks support
    
    When SUPPORTS_RICH_FUNCTION_OUTPUT is False, image/file items from tool
    results are injected as a follow-up user message so the model can still
    process the visual content via Foundry's supported user message format.
    
    * Xfail Foundry image integration test for the meantime
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: [BREAKING] update to v1.0.0 (#5062)
    * updates to final deprecated pieces and versions
    
    * fix mypy
    
    * fix readme links
  • Python: [BREAKING] Python: move Azure AI embeddings to Foundry (#5056)
    * renamed AzureAIINferenceEmbeddings and lazy load azure-cosmos and env var rename
    
    * updated coverage
    
    * fix readme
  • [BREAKING] Python: Refactor workflows kwargs (#5010)
    * Refactor workflows kwargs usage
    
    * Update sample
    
    * Add tests
    
    * Update samples
    
    * Fix formatting
    
    * Comments
    
    * Comments 2
    
    * Comments 3
    
    * Fix test and typing
  • Python: Fix duplicate system message from instructions (#5049) (#5051)
    Add deduplication to `prepend_instructions_to_messages()` to skip
    instructions that are already present as leading messages with the
    same role and text. This prevents duplicate system messages when
    instructions are injected by multiple layers (e.g. Agent + chat client).
    
    Fixes #5049
  • Python: updated declarative samples and handling of non-pydantic response formats (#5022)
    * updated declarative samples and handling of non-pydantic response formats
    
    * fixed from comments
    
    * update docstring
  • Python: [BREAKING] Standardize model selection on model (#4999)
    * Refactor Anthropic model option and provider clients
    
    Rename the Anthropic client model option from model_id to model, add provider-specific Anthropic wrappers for Foundry, Bedrock, and Vertex, and expose them through the Anthropic, Foundry, Amazon, and Google namespaces. Update core option handling, docs, samples, and tests accordingly.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix Anthropic skills sample typing
    
    Cast the Anthropic beta client to Any in the skills sample so the pre-commit sample pyright check no longer fails on beta skills and files endpoints that are not exposed by the current SDK stubs.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * undo sample mypy
    
    * Retry CI after transient external failures
    
    Retrigger PR validation after an unrelated Copilot review workflow SAML failure and a transient external tau2 git fetch failure in the Windows Python test setup.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback on model option merging
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address Anthropic compatibility review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * moved all to `model`
    
    * fixes for azure ai search
    
    * Python: standardize remaining sample env var names
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: fix foundry-local pyright compatibility
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated env vars in cicd
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: [BREAKING] update context provider APIs, middleware, and per-service-call history persistence (#4992)
    * Rename provider base APIs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Allow provider-added chat and function middleware
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Simulate service-stored history per model call
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix typing regressions in CI
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix response ID suppression review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Rename per-service-call history persistence APIs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address context persistence review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Stabilize markdown sample docs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Persist service continuation state per call
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix _add_text_reasoning_content to preserve id during coalescing (#4862)
    * Fix _add_text_reasoning_content dropping id during coalescing (#4852)
    
    Preserve the id field (rs_* identifier) when coalescing text_reasoning
    Content objects by passing id=self.id or other.id to the Content
    constructor. This fixes the encrypted reasoning round-trip where the
    missing id prevented _prepare_content_for_openai from including it in
    the serialized reasoning item.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Fix `_add_text_reasoning_content` to preserve `id` during coalescing
    
    Fixes #4852
    
    * Raise AdditionItemMismatch on conflicting text_reasoning ids (#4852)
    
    Detect when both operands have different non-empty ids during
    text_reasoning Content coalescing and raise AdditionItemMismatch
    instead of silently keeping one. This prevents mis-associating
    encrypted_content during round-trips.
    
    Also adds tests for conflicting ids and the neither-has-id edge case.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #4852: Python: [Bug]: Content._add_text_reasoning_content drops id during coalescing, breaking encrypted reasoning round-trip
    
    * test fix
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add Python feature lifecycle decorators for released APIs (#4975)
    * Add Python feature lifecycle decorators
    
    Introduce reusable experimental and release-candidate decorators for released packages, migrate the Skills APIs to the new staged metadata and warning system, and add lifecycle guidance plus samples.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix Python CI follow-ups
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Preserve protocol runtime checks
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • 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: [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: 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: [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: [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: 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: 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: 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 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: 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>