Commit Graph

621 Commits

  • Python: Fix as_agent() not defaulting name/description from client properties (#4484)
    * Fix as_agent() not defaulting name/description from client properties
    
    AzureAIClient.as_agent() and AzureAIAgentClient.as_agent() now fall back
    to self.agent_name and self.agent_description when name/description are
    not explicitly passed. This ensures Agent.name is populated for
    telemetry spans without requiring callers to repeat the name.
    
    Fixes #4471
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: use is None checks instead of truthiness
    
    Switch from name or self.agent_name to explicit is None checks so
    that callers can intentionally pass empty strings without them being
    replaced by client defaults. Added edge-case tests for empty strings.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Update docstrings to document name/description defaulting behavior
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Forward runtime kwargs to skill resource functions (#4417)
    * support code skills
    
    * address pr review comments
    
    * address package and syntax checks
    
    * address pr review comments
    
    * address pr review comment
    
    * address failed check
    
    * rename agentskill and agetnskillprovider
    
    * move agent skills related assets to _skills.py
    
    * address pr review comments
    
    * address review comments
    
    * support kwargs
    
    * address pr review feedback
  • Python: Fix Python pyright package scoping and typing remediation (#4426)
    * Fix Python pyright package scoping and typing remediation
    
    Implements issue #4407 by removing the root pyright include, adding package-level pyright includes, and resolving pyright/mypy typing issues across Python packages. Also cleans unnecessary casts and applies line-level, rule-specific ignores where external libraries are too dynamic.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Reduce pyright cost in handoff cloning
    
    Simplify cloned_options construction in HandoffAgentExecutor to avoid expensive TypedDict narrowing/inference in _handoff.py, which was causing pyright to spend a long time in orchestrations.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix types
    
    * Fix lint and type-check regressions
    
    Resolve current Python package check failures across lint, pyright, and mypy after recent code changes, including purview/declarative pyright issues and multiple ruff simplification findings.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fixed hooks
    
    * Stabilize package tests and test tasks
    
    Resolve cross-package non-integration test failures, simplify streaming type flow, harden locale/culture handling, and standardize package test poe tasks to exclude integration tests where applicable.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * lots of small fixes
    
    * Fix current Python test regressions
    
    Address current failing unit tests in azure-ai, bedrock, and azure-cosmos while keeping Bedrock parsing logic inline (no new static helper methods).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * small fixes
    
    * small fixes
    
    * removed pydantic from json
    
    * final updates
    
    * fix core
    
    * fix tests
    
    * fix obser
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add propagate_session to as_tool() for session sharing in agent-as-tool scenarios (#4439)
    * Python: Add propagate_session parameter to as_tool() for session sharing
    
    Add opt-in session propagation in agent-as-tool scenarios. When
    propagate_session=True, the parent agent's AgentSession is forwarded
    to the sub-agent's run() call, allowing both agents to share session
    state (history, metadata, session_id).
    
    - Add propagate_session parameter to BaseAgent.as_tool() (default False)
    - Include session in additional_function_arguments so it flows to tools
    - Add 3 tests for propagation on/off and shared state verification
    - Add sample showing session propagation with observability middleware
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Clarify propagate_session docstring per review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: [BREAKING] Support code-defined agent skills (#4387)
    * support code skills
    
    * address pr review comments
    
    * address package and syntax checks
    
    * address pr review comments
    
    * address pr review comment
    
    * address failed check
    
    * rename agentskill and agetnskillprovider
    
    * move agent skills related assets to _skills.py
    
    * address pr review comments
    
    * address review comments
  • Python: feat(claude): add plugins, setting_sources, thinking, and effort options to ClaudeAgentOptions (#4425)
    * feat(claude): add plugins, setting_sources, thinking, and effort options
    
    Add four Claude Agent SDK options to ClaudeAgentOptions that are clean
    passthroughs with no abstraction conflicts:
    
    - plugins: load Claude Code plugins programmatically via SdkPluginConfig
    - setting_sources: control which .claude settings files are loaded
    - thinking: modern extended thinking config (adaptive/enabled/disabled)
    - effort: control thinking depth (low/medium/high/max)
    
    * feat(claude): remove max_thinking_tokens, add plugins/setting_sources/thinking/effort
    
    Remove the deprecated max_thinking_tokens field from ClaudeAgentOptions
    in favor of the new thinking field (ThinkingConfig).
    
    Add four Claude Agent SDK options as clean passthroughs:
    - plugins: load Claude Code plugins via SdkPluginConfig
    - setting_sources: control which .claude settings files are loaded
    - thinking: extended thinking config (adaptive/enabled/disabled)
    - effort: thinking depth control (low/medium/high/max)
  • Python: Fix PowerFx eval crash on non-English system locales by setting CurrentUICulture to en-US (#4408)
    * Fix #4321: Set CurrentUICulture to en-US in PowerFx eval()
    
    On non-English systems, CultureInfo.CurrentUICulture causes PowerFx to
    emit localized error messages. The existing ValueError guard only matches
    English strings ("isn't recognized", "Name isn't valid"), so undefined
    variable errors crash instead of returning None gracefully.
    
    Fix: save and restore CurrentUICulture alongside CurrentCulture before
    calling engine.eval(), ensuring error messages are always in English.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Reuse single CultureInfo instance to avoid redundant allocations
    
    Cache CultureInfo("en-US") in a local variable instead of instantiating
    it twice per eval() call, as suggested in PR review.
    
    Fixes #4321
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add assertion for CurrentUICulture restoration after eval
    
    Assert that the production code's finally-block correctly restores
    CurrentUICulture to it-IT after eval returns, covering future
    regressions where the culture could leak.
    
    The CultureInfo caching suggestion (comment #2) was already
    implemented in the production code.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix MCP tools duplicated on second turn when runtime tools are present (#4432)
    * Fix MCP tools duplicated on second turn when runtime tools are present
    
    When AG-UI's collect_server_tools pre-expands MCP functions on turn 2
    (after the MCP server is connected), _prepare_run_context unconditionally
    appends them again from self.mcp_tools, duplicating every MCP tool.
    
    Skip MCP functions whose names already exist in the final tool list,
    following the same name-based dedup pattern used in _merge_options.
    
    Fixes #4381
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * mypy fix
    
    * Remove issue-specific references from test docstring
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Upgraded azure-ai-projects to 2.0.0b4 (#4438)
    * Upgraded azure-ai-projects to 2.0.0b4
    
    * Fixed tests
  • Python: Fix: Parse oauth_consent_request events in Azure AI client (#4197)
    * Fix: Parse oauth_consent_request events in Azure AI client (#3950)
    
    When Azure AI Agent Service returns an oauth_consent_request output item
    for OAuth-protected MCP tools, the base OpenAI responses parser drops it
    (hits case _ default branch). This causes agent runs to complete silently
    with zero content.
    
    Changes:
    - Add oauth_consent_request ContentType and Content.from_oauth_consent_request()
      factory with consent_link field and user_input_request=True
    - Override _parse_response_from_openai and _parse_chunk_from_openai in
      RawAzureAIClient to intercept Azure-specific oauth_consent_request items
    - Add _emit_oauth_consent helper in AG-UI to emit CustomEvent for frontends
    - Add tests proving base parser drops the event and Azure AI override catches it
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * addressed comment
    
    * addressed comments
    
    * addressed comments
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add file_ids and data_sources support to get_code_interpreter_tool() (#4201)
    * Python: Add file_ids and data_sources support to AzureAIAgentClient.get_code_interpreter_tool()
    
    Update the factory method to accept file_ids and data_sources keyword
    arguments, matching the underlying azure.ai.agents SDK CodeInterpreterTool
    constructor. This enables users to attach uploaded files for code
    interpreter analysis.
    
    Fixes #4050
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * addressed comments
    
    * addressed comments
    
    * Add per-message file attachment support for AzureAIAgentClient
    
    Add hosted_file handling in _prepare_messages() to convert
    Content.from_hosted_file() into MessageAttachment on ThreadMessageOptions.
    This enables per-message file scoping for code interpreter, matching the
    underlying Azure AI Agents SDK MessageAttachment pattern.
    
    - Add hosted_file case in _prepare_messages() match statement
    - Import MessageAttachment from azure.ai.agents.models
    - Add sample for per-message CSV file attachment with code interpreter
    - Add employees.csv test data file
    - Add 3 unit tests for hosted_file attachment conversion
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review: validation, fix assertions, remove MessageAttachment
    
    - Add empty string validation in resolve_file_ids()
    - Add test for Content with file_id=None
    - Add test for empty string file_ids
    - Revert MessageAttachment/hosted_file handling from _prepare_messages()
      (moved to separate issue #4352 for proper design)
    - Remove per-message file upload sample and employees.csv
    - Keep data_sources assertion as-is (dict keyed by asset_identifier)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix workflow tests pyright warnings (#4362)
    * Fix workflow tests pyright warnings
    
    * Update uv.lock
    
    * Fix pyright
    
    * Comments
    
    * Update root pyproject pyright setting
    
    * Update core pyproject pyright setting
    
    * Update core pyproject pyright setting
  • Python: Add OpenTelemetry instrumentation to ClaudeAgent (#4278) (#4326)
    * Python: Add OpenTelemetry instrumentation to ClaudeAgent (#4278)
    
    Add inline telemetry to ClaudeAgent.run() so that enable_instrumentation()
    emits invoke_agent spans and metrics. Covers both streaming and
    non-streaming paths using the same observability helpers as
    AgentTelemetryLayer. Adds 5 unit tests for telemetry behavior.
    
    Co-Authored-By: amitmukh <amimukherjee@microsoft.com>
    
    * Address PR review feedback for ClaudeAgent telemetry
    
    - Add justification comment for private observability API imports
    - Pass system_instructions to capture_messages for system prompt capture
    - Use monkeypatch instead of try/finally for test global state isolation
    
    Co-Authored-By: amitmukh <amitmukh@users.noreply.github.com>
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * Adopt AgentTelemetryLayer instead of inline telemetry
    
    Restructure ClaudeAgent to inherit from AgentTelemetryLayer via a
    _ClaudeAgentRunImpl mixin, eliminating duplicated telemetry code and
    private API imports.
    
    MRO: ClaudeAgent → AgentTelemetryLayer → _ClaudeAgentRunImpl → BaseAgent
    
    - Remove inline _run_with_telemetry / _run_with_telemetry_stream methods
    - Remove private observability helper imports (_capture_messages, etc.)
    - Add default_options property mapping system_prompt → instructions
    - Net -105 lines by reusing core telemetry layer
    
    Co-Authored-By: amitmukh <amitmukh@users.noreply.github.com>
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * Fix mypy: align _ClaudeAgentRunImpl.run() signature with AgentTelemetryLayer.run()
    
    Remove explicit `options` parameter from mixin's run() signature and
    extract it from **kwargs to match AgentTelemetryLayer's signature.
    Also align overload return types (ResponseStream, Awaitable) to match.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * Introduce RawClaudeAgent following framework's RawAgent/Agent pattern
    
    Replace private _ClaudeAgentRunImpl mixin with public RawClaudeAgent
    class that contains all core logic (init, run, lifecycle, tools).
    ClaudeAgent becomes a thin wrapper that adds AgentTelemetryLayer.
    
    - RawClaudeAgent(BaseAgent): full implementation without telemetry
    - ClaudeAgent(AgentTelemetryLayer, RawClaudeAgent): adds OTel tracing
    - Export RawClaudeAgent from package __init__.py
    
    Users who want to skip telemetry or provide their own can use
    RawClaudeAgent directly.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * Address review nits: trim RawClaudeAgent docstring, fix import paths
    
    - Simplify RawClaudeAgent docstring to a single basic example (not the
      primary entry point for most users)
    - Use agent_framework.anthropic import path in docstrings instead of
      direct agent_framework_claude path
    - Add RawClaudeAgent to agent_framework.anthropic lazy re-exports
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    ---------
    
    Co-authored-by: Amit Mukherjee <amimukherjee@microsoft.com>
    Co-authored-by: amitmukh <amitmukh@users.noreply.github.com>
    Co-authored-by: Claude <noreply@anthropic.com>
    Co-authored-by: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com>
  • Python: Fix StandardMagenticManager to propagate session to manager agent (#4409)
    * Fix #4371: Propagate session to manager agent in StandardMagenticManager
    
    StandardMagenticManager._complete() was calling self._agent.run(messages)
    without passing a session. This caused context providers (e.g.
    RedisHistoryProvider) configured on the manager agent to silently fail,
    as each call created a new ephemeral session with a different session_id.
    
    Changes:
    - Create an AgentSession in StandardMagenticManager.__init__()
    - Pass session=self._session in _complete() calls to agent.run()
    - Persist/restore the session in checkpoint save/restore methods
    - Add regression tests for session propagation and checkpoint round-trip
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add type: ignore[reportPrivateUsage] to private attribute assertions in tests
    
    Address PR review feedback: add # type: ignore[reportPrivateUsage] comments
    to _session attribute accesses in the new regression tests, matching the
    existing convention used elsewhere in test_magentic.py (e.g., lines 401-406).
    
    The @pytest.mark.asyncio decorator is not needed because pyproject.toml
    sets asyncio_mode = "auto".
    
    Fixes #4371
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: use getattr for private _session access in tests (#4371)
    
    Replace direct mgr._session access with getattr(mgr, "_session") to avoid
    reportPrivateUsage type-checking warnings without needing type: ignore comments.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Address PR review: fix session restore guard and improve test robustness (#4371)
    
    - Use 'is not None' instead of truthiness check for session_payload restore
    - Use getattr() for private _session attribute access in tests
    - Add backward-compatibility test for on_checkpoint_restore with empty state
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Make non-async tests plain def to avoid pytest-asyncio dependency (#4409)
    
    Tests that never await anything don't need to be async. Using plain def
    ensures they always run regardless of pytest-asyncio configuration.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Added Shell tool (#4339)
    * Added shell tool
    
    * Fixed CI error
    
    * Add ShellTool support for OpenAI and Anthropic providers
    
    - Add shell_tool_call, shell_tool_result, and shell_command_output content types
    - Add ShellTool class and shell_tool decorator to core
    - Add get_hosted_shell_tool() to OpenAI Responses client
    - Handle shell_call and shell_call_output parsing in OpenAI (sync and streaming)
    - Map ShellTool to Anthropic bash tool API format
    - Parse bash_code_execution_tool_result as shell_tool_result in Anthropic
    - Add unit tests for all new functionality
    - Add sample scripts for hosted and local shell execution
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Addressed comments
    
    * Reverted ruff change
    
    * Fixed tests
    
    * Addressed comments
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix IndexError when reasoning models produce reasoning-only messages in Magentic-One workflow (#4413)
    * Fix IndexError when reasoning models return no text content (#4384)
    
    In _prepare_message_for_openai(), the text_reasoning case unconditionally
    accessed all_messages[-1] to attach reasoning_details. When a reasoning
    model (e.g. gpt-5-mini) returns reasoning_details without text content,
    all_messages is empty, causing an IndexError.
    
    Guard the access by initializing all_messages with the current args dict
    when it is empty, so reasoning_details can be safely attached.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: buffer reasoning details for valid message payloads (#4384)
    
    - Buffer pending reasoning details and attach to the next message with
      content/tool_calls, avoiding standalone reasoning-only messages.
    - When reasoning is the only content, emit a message with empty content
      to satisfy Chat Completions schema requirements.
    - Strengthen test assertions to verify text+reasoning co-location and
      that all messages with reasoning_details also have content or tool_calls.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix text_reasoning handling: always buffer and tighten tests (#4384)
    
    - Always buffer reasoning into pending_reasoning instead of conditionally
      attaching to the previous message via fragile all_messages emptiness check
    - Attach buffered reasoning to last message at end-of-loop when no subsequent
      content consumed it
    - Assert exact content values (content == '' not in ('', None))
    - Assert exact list lengths (== 1 not >= 1) for stronger regression guards
    - Add test for reasoning before FunctionCallContent
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add Azure Cosmos history provider package (#4271)
    * Created cosmos history provider
    
    * add marker
    
    * Python: address Cosmos PR feedback
    
    - address provider/test/sample review feedback and cleanup typing
    - add cosmos integration test coverage and skip gating
    - add dedicated cosmos emulator jobs to python merge/integration workflows
    - switch cosmos workflow execution to package poe integration-tests task
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: handle empty Cosmos session id
    
    - replace default partition fallback for empty session_id
    - log warning and generate GUID when session_id is empty
    - update unit tests to validate GUID fallback behavior
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix sample
    
    * fix cross partition query
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add regression tests for Entry JoinExecutor Workflow.Inputs initialization (#4335)
    * Python: Add regression tests for #3948 - Entry JoinExecutor initializes Workflow.Inputs
    
    Add tests verifying that when workflow.run() is called with a dict or string
    input, the Entry node (JoinExecutor with kind: 'Entry') correctly initializes
    Workflow.Inputs via _ensure_state_initialized so that:
    - Expressions like =inputs.age resolve to the correct value
    - Conditions like =Local.age < 13 evaluate based on actual input (not blank/0)
    - String inputs populate both inputs.input and System.LastMessage.Text
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Fix D420 and RUF070 lint errors across packages
    
    * Revert _workflow.py yield-inside-context-manager changes
    
    Moving yield inside `with _framework_event_origin()` blocks in the
    async generator causes ContextVar token reset failures on Python 3.12
    Windows. The token stays un-reset while the generator is suspended,
    and async generator finalization in a different contextvars.Context
    triggers ValueError, corrupting OpenTelemetry span state and causing
    test_span_creation_and_attributes to see leaked spans.
    
    Keep yields outside the context manager blocks to ensure tokens are
    reset immediately before the generator suspends.
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: fix(python): Handle thread.message.completed event in Assistants API streaming (#4333)
    * fix: handle thread.message.completed event in Assistants API streaming
    
    Previously, `thread.message.completed` events fell through to the
    catch-all `else` branch and yielded empty `ChatResponseUpdate` objects,
    silently discarding fully-resolved annotation data (file citations,
    file paths, and their character-offset regions).
    
    This commit adds a dedicated handler for `thread.message.completed`
    that:
    - Walks the completed ThreadMessage.content array
    - Extracts text blocks with their fully-resolved annotations
    - Maps FileCitationAnnotation and FilePathAnnotation to the
      framework's Annotation type with proper TextSpanRegion data
    - Yields a ChatResponseUpdate containing the complete text and
      annotations
    
    Fixes #4322
    
    * test: add tests for thread.message.completed annotation handling
    
    Tests cover:
    - File citation annotation extraction
    - File path annotation extraction
    - Multiple annotations on a single text block
    - Text-only messages (no annotations)
    - Non-text blocks are skipped
    - Mixed content blocks (text + image)
    - Conversation ID propagation
    
    * fix: address Copilot review - add quote field and log unrecognized annotations
    
    - Include `quote` from `annotation.file_citation.quote` in
      `additional_properties` for FileCitationAnnotation, preserving the
      exact cited text snippet from the source file
    - Add `else` clause to log unrecognized annotation types at debug level,
      consistent with the pattern in `_responses_client.py`
    - Add `import logging` and module-level logger
    
    * test: add coverage for quote field and unrecognized annotation logging
    
    - test_message_completed_with_file_citation_quote: verifies quote is
      included in additional_properties
    - test_message_completed_with_file_citation_no_quote: verifies quote
      is omitted when None
    - test_message_completed_unrecognized_annotation_logged: verifies
      unknown annotation types are logged at debug level and skipped
    
    * fix: address reviewer nits — logger name convention + annotation type string
    
    Per @giles17's review:
    - Use logging.getLogger('agent_framework.openai') to match module convention
    - Simplify debug message to use annotation.type instead of type().__name__
    
    * refactor: move message.completed tests into consolidated test file
    
    Per @giles17's review: moved all tests from test_assistants_message_completed.py
    into test_openai_assistants_client.py and deleted the standalone file.
    
    * fix: resolve mypy no-redef and ruff RET504 lint errors
    
    - Remove duplicate type annotation for 'ann' variable (no-redef)
    - Return directly from fixture instead of unnecessary assignment (RET504)
    
    * fix: rename annotation variable in completed block to fix mypy type conflict
    
    The 'annotation' loop variable in thread.message.completed has type
    FileCitationAnnotation | FilePathAnnotation, which conflicts with the
    delta block's 'annotation' of type FileCitationDeltaAnnotation |
    FilePathDeltaAnnotation. Renamed to 'completed_annotation' to avoid
    mypy 'Incompatible types in assignment' error.
    
    * fix: remove quote field from FileCitationAnnotation handling
    
    ---------
    
    Co-authored-by: Giles Odigwe <79032838+giles17@users.noreply.github.com>
  • Python: Fix walrus operator precedence for model_id kwarg in AzureOpenAIResponsesClient (#4310)
    * Fix walrus operator precedence for model_id in AzureOpenAIResponsesClient (#4299)
    
    Add parentheses around the walrus assignment so model_id receives the
    actual string value instead of the boolean result of
    `kwargs.pop(...) and not deployment_name`.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: replace walrus with explicit None check, add edge-case tests (#4299)
    
    - Replace walrus operator with explicit assignment and 'is not None'
      check to avoid boolean-coercion pitfalls (empty string now correctly
      surfaces as ValueError instead of silently falling back)
    - Add test: deployment_name takes precedence over model_id kwarg
    - Add test: model_id='' raises ValueError
    - Add test: model_id=None falls back to env var
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add explicit validation for empty model_id in AzureOpenAIResponsesClient
    
    Reject empty or whitespace-only model_id with ValueError instead of
    silently passing an empty deployment name downstream. This ensures the
    test_init_model_id_kwarg_empty_string test correctly validates behavior
    defined in production code rather than relying on downstream validation.
    
    Addresses PR review feedback for #4299.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Simplify model_id handling using walrus operator
    
    Addresses review comment on PR #4310.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Restore explicit model_id validation to fix test failures (#4299)
    
    The walrus operator refactor silently dropped the empty-string validation,
    causing test_init_model_id_kwarg_empty_string to fail. Restore the explicit
    None check and ValueError raise for empty model_id.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Revert "Restore explicit model_id validation to fix test failures (#4299)"
    
    This reverts commit 1d2965fff6.
    
    * Revert to walrus operator fix per review feedback
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: .NET: Fix .NET conversation memory in DevUI (#3484) (#4294)
    * Fix .NET conversation memory in DevUI (#3484)
    
    * formatting fixes
    
    * fix memory regression in python devui , fix for #4123
    
    * Fix for #3983: Added _get_event_type() helper that safely accesses event type on both objects (.type) and dicts (.get("type")). Replaced all 4 bare event.type accesses in _executor.py (lines 267, 477, 499, 523).
    
    Root cause: PR #3690 changed event.__class__.__name__ == "RequestInfoEvent" (safe) to event.type == "request_info" (crashes on dicts), but _execute_workflow still yields raw dicts on error paths.
    
    Test: test_workflow_error_yields_dict_event_without_crash — mocks a workflow that raises, verifies execute_entity consumes the dict error events without crashing.
    
    * format fixes
    
    * lint fixes
  • Python: Fix executor handler type resolution when using from __future__ import annotations (#4317)
    * Python: Fix Executor handler type checking with __future__ annotations (#3898)
    
    Use typing.get_type_hints() in _validate_handler_signature to resolve
    string annotations from `from __future__ import annotations`. This
    mirrors the fix applied to FunctionExecutor in #2308.
    
    When __future__ annotations are enabled, type annotations are stored as
    strings. The handler decorator was passing these strings directly to
    validate_workflow_context_annotation, which uses typing.get_origin and
    returns None for strings, causing a ValueError.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback for #3898: improve error handling and test coverage
    
    - Wrap typing.get_type_hints() in try/except to provide a descriptive
      ValueError mentioning the handler name when annotations cannot be resolved
    - Strengthen bare context test to assert output_types and workflow_output_types
    - Add test for @handler(input=..., output=...) with future annotations
      covering the skip_message_annotation branch
    - Add test for union-type context annotations with future annotations
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Narrow exception catch and add test for unresolvable annotations (#3898)
    
    - Narrow except clause from bare Exception to (NameError, AttributeError,
      TypeError) to avoid masking unexpected errors.
    - Add test_handler_unresolvable_annotation_raises to verify that a handler
      with a forward-reference to a non-existent type raises ValueError with
      the expected message.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix #3898: fall back to raw annotations when get_type_hints fails
    
    When typing.get_type_hints(func) raises NameError (unresolvable forward
    ref), AttributeError, RecursionError, or any other exception, fall back
    to the raw parameter annotations instead of raising a ValueError.
    This matches the suggestion from @moonbox3 on PR #4317.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix test to match new fallback behavior when get_type_hints fails (#3898)
    
    The code now falls back to raw string annotations instead of raising
    'Failed to resolve type annotations'. A ValueError is still raised when
    the raw string ctx annotation is not a valid WorkflowContext type, so
    update the test to match on ValueError without checking the message.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pyupgrade: remove unnecessary string annotation quote
    
    * Add noqa for intentionally undefined name in annotation test
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Tuning auto sample validation workflow (#4218)
    * Tuning validate-01-get-started
    
    * Add gh token
    
    * Add model
    
    * enable debug log
    
    * bump up timeout for testing purposes
    
    * Test cli is working
    
    * Fix end quote
    
    * Run gh auth
    
    * Run gh auth trail 2
    
    * Run gh auth trail 3
    
    * Test token
    
    * Add zcure login
    
    * Add zcure login 2
    
    * Add zcure login 3
    
    * Add zcure login 4
    
    * Extract common actions
    
    * Extract common actions 2
    
    * Correct env vars
    
    * Print outputs to action console
    
    * Disable end-to-end samples
    
    * Fix ruff errors
    
    * Fix ruff errors 2
    
    * Revert workflow changes to fix tests
    
    * Revert workflow changes to fix tests 2
    
    * Revert workflow changes to fix tests 3
    
    * Revert workflow changes to fix tests 4
  • Python: Fix agent option merge to support dict-defined tools (#4314)
    * Fix _merge_options dropping dict-defined tools (#4303)
    
    _merge_options used getattr(tool, 'name', None) to de-duplicate tools,
    which returns None for dict-style tool definitions. This caused all
    override dict tools to be treated as duplicates of each other and of any
    base dict tools, silently dropping them.
    
    Add _get_tool_name() helper that extracts the name from both object-style
    tools (via .name attribute) and dict-style tools (via tool['function']['name']).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: fix None dedup bug and add comprehensive tests (#4303)
    
    - Exclude None from existing_names set so nameless/malformed tools are
      not silently deduplicated against each other
    - Add test for cross-type dedup (dict tool + object tool with same name)
    - Add test verifying nameless tools are preserved (not falsely deduped)
    - Add unit tests for _get_tool_name edge cases: missing function key,
      non-dict function value, missing name, no name attribute, non-dict
      inputs, and valid dict/object tools
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix single-tool input handling in OpenAIResponsesClient._prepare_tools_for_openai (#4312)
    * Fix OpenAIResponsesClient mishandling single-tool inputs (#4304)
    
    Use normalize_tools() in _prepare_tools_for_openai to wrap single tools
    (FunctionTool or dict) in a list before iteration, consistent with the
    chat client implementation.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback for #4304
    
    - Use precise type annotation matching normalize_tools/OpenAIChatClient signature
      instead of collapsed Sequence[Any] | Any | None
    - Move emptiness guard after normalize_tools() call so single falsy tool
      objects are not silently swallowed
    - Import ToolTypes for the type annotation
    - Expand test_prepare_tools_for_openai_single_function_tool assertions to
      verify parameters, strict, and parameter schema fields
    - Add test_prepare_tools_for_openai_none to verify None input returns []
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix WorkflowAgent not persisting response messages to session history (#1694) (#4319)
    WorkflowAgent._run_impl() and _run_stream_impl() did not set
    session_context._response before calling _run_after_providers().
    This caused InMemoryHistoryProvider.after_run() to see context.response
    as None, so response messages were never stored in the session.
    
    On subsequent runs, the workflow only received prior user inputs without
    assistant responses, breaking multi-turn conversations.
    
    Fix: Set session_context._response to the workflow result before running
    after_run providers, matching the behavior of the regular Agent class.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Map file citation annotations from TextDeltaBlock in Assistants API streaming (#4316) (#4320)
    During Assistants API streaming, TextDeltaBlock.text.annotations was
    ignored when creating Content objects. This caused raw placeholder
    strings like 【4:0†source】 to pass through to downstream consumers
    (including AG-UI) instead of being resolved to citation metadata.
    
    Map FileCitationDeltaAnnotation and FilePathDeltaAnnotation from
    delta_block.text.annotations to Annotation objects on the Content,
    consistent with the existing patterns in _responses_client.py and
    _chat_client.py.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Preserve workflow run kwargs when continuing with run(responses=...) (#4296)
    * fix(python): preserve workflow run kwargs on response continuation (#4293)
    
    When continuing a paused workflow with run(responses=...), the existing
    run kwargs stored in state were unconditionally overwritten with an empty
    dict. This caused subsequent agent invocations to lose the original run
    context (e.g., custom_data, user tokens).
    
    Now kwargs are only overwritten when:
    - New kwargs are explicitly provided (override), or
    - State was just cleared for a fresh run (initialize to {})
    
    On continuation without new kwargs, existing kwargs are preserved.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback for #4293
    
    - Use consistent get_state(key, {}) default pattern in _agent_executor.py
      and _workflow_executor.py instead of get_state(key) or {} to safely
      handle missing WORKFLOW_RUN_KWARGS_KEY
    - Add test for empty-value kwargs on continuation (custom_data={}) to
      verify the is-not-None boundary between overwrite and preserve
    - Add test for reset_context=True with no kwargs to exercise the elif
      branch that initializes WORKFLOW_RUN_KWARGS_KEY to {}
    - Add len assertion to override test for consistency
    - Document kwargs-collapsing behavior at the public API call site
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Strip reserved kwargs in AgentExecutor to prevent duplicate-argument TypeError (#4298)
    * Python: Strip reserved kwargs in AgentExecutor to prevent collision (#4295)
    
    workflow.run(session=...) passed 'session' through to agent.run() via
    **run_kwargs while AgentExecutor also passes session=self._session
    explicitly, causing TypeError: got multiple values for keyword argument.
    
    _prepare_agent_run_args now strips reserved params (session, stream,
    messages) from run_kwargs and logs a warning when they are present.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback for #4295
    
    - Use _RESERVED_RUN_PARAMS constant in stripping loop instead of
      hardcoded tuple to maintain single source of truth
    - Trim frozenset to only stripped keys (session, stream, messages);
      options and additional_function_arguments have separate merge logic
    - Fix caplog type annotation to use TYPE_CHECKING pattern
    - Assert options return value in reserved-kwarg stripping test
    - Add test for multiple reserved kwargs supplied simultaneously
    - Add integration test for messages= kwarg via workflow.run()
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Tighten HandoffBuilder to require Agent instead of SupportsAgentRun (#4301) (#4302)
    HandoffBuilder.participants() accepted SupportsAgentRun by API contract,
    but build() failed at runtime because _prepare_agent_with_handoffs()
    requires Agent instances for cloning, tool injection, and middleware.
    
    Fix: Update all public type hints, docstrings, and validation in
    HandoffBuilder and HandoffAgentExecutor to require Agent explicitly.
    The isinstance check is now performed early in participants() with a
    clear error message explaining why Agent is required.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix response_format resolution in streaming finalizer (#4291)
    * Python: Fix AgentResponse.value being None when streaming workflow (#3970)
    
    The streaming path in BaseAgent.run() used the raw 'options' parameter
    (passed by the caller) to bind response_format into the outer stream's
    finalizer. When response_format was set in default_options rather than
    runtime options, it was missing from the finalizer and value was None.
    
    Fix: Use the merged chat_options from the run context (via ctx_holder),
    matching the non-streaming path which already uses ctx['chat_options'].
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #3970: safer ctx access, add test coverage
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix Bedrock embedding test stub missing meta attribute (#4287)
    * Fix Bedrock embedding test stub missing meta attribute
    
    * Increase test coverage so gate passes
  • Python / .NET Samples - Restructure and Improve Samples (Feature Branc… (#4092)
    * Python: .NET Samples - Restructure and Improve Samples (Feature Branch) (#4091)
    
    * Moved by agent (#4094)
    
    * Fix readme links
    
    * .NET Samples - Create `04-hosting` learning path step (#4098)
    
    * Agent move
    
    * Agent reorderd
    
    * Remove A2A section from README 
    
    Removed A2A section from the Getting Started README.
    
    * Agent fixed links
    
    * Fix broken sample links in durable-agents README (#4101)
    
    * Initial plan
    
    * Fix broken internal links in documentation
    
    Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
    
    * Revert template link changes; keep only durable-agents README fix
    
    Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
    
    * .NET Samples - Create `03-workflows` learning path step (#4102)
    
    * Fix solution project path
    
    * Python: Fix broken markdown links to repo resources (outside /docs) (#4105)
    
    * Initial plan
    
    * Fix broken markdown links to repo resources
    
    Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
    
    * Update README to rename .NET Workflows Samples section
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
    
    * .NET Samples - Create `02-agents` learning path step (#4107)
    
    * .NET: Fix broken relative link in GroupChatToolApproval README (#4108)
    
    * Initial plan
    
    * Fix broken link in GroupChatToolApproval README
    
    Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
    
    * Update labeler configuration for workflow samples
    
    * .NET - Reorder Agents samples to start from Step01 instead of Step04 (#4110)
    
    * Fix solution
    
    * Resolve new sample paths
    
    * Move new AgentSkills and AgentWithMemory_Step04 samples
    
    * Fix link
    
    * Fix readme path
    
    * fix: update stale dotnet/samples/Durable path reference in AGENTS.md
    
    Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
    
    * Moved new sample
    
    * Update solution
    
    * Resolve merge (new sample)
    
    * Sync to new sample - FoundryAgents_Step21_BingCustomSearch
    
    * Updated README
    
    * .NET Samples - Configuration Naming Update (#4149)
    
    * .NET: Restore AzureFunctions index parity with ConsoleApps under DurableAgents samples (#4221)
    
    * Clean-up `05_host_your_agent`
    
    * Config setting consistency
    
    * Refine samples
    
    * AGENTS.md
    
    * Move new samples
    
    * Re-order samples
    
    * Move new project and fixup solution
    
    * Fixup model config
    
    * Fix up new UT project
    
    ---------
    
    Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
  • Update Python package versions to rc2 (#4258)
    - Bump core and azure-ai to 1.0.0rc2
    - Bump preview packages to 1.0.0b260225
    - Update dependencies to >=1.0.0rc2
    - Add CHANGELOG entries for changes since rc1
    - Update uv.lock
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Phase 2: Embedding clients for Ollama, Bedrock, and Azure AI Inference (#4207)
    * Phase 2: Embedding clients for Ollama, Bedrock, and Azure AI Inference
    
    Add embedding client implementations to existing provider packages:
    
    - OllamaEmbeddingClient: Text embeddings via Ollama's embed API
    - BedrockEmbeddingClient: Text embeddings via Amazon Titan on Bedrock
    - AzureAIInferenceEmbeddingClient: Text and image embeddings via Azure AI
      Inference, supporting Content | str input with separate model IDs for
      text (AZURE_AI_INFERENCE_EMBEDDING_MODEL_ID) and image
      (AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL_ID) endpoints
    
    Additional changes:
    - Rename EmbeddingCoT -> EmbeddingT, EmbeddingOptionsCoT -> EmbeddingOptionsT
    - Add otel_provider_name passthrough to all embedding clients
    - Register integration pytest marker in all packages
    - Add lazy-loading namespace exports for Ollama and Bedrock embeddings
    - Add image embedding sample using Cohere-embed-v3-english
    - Add azure-ai-inference dependency to azure-ai package
    
    Part of #1188
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix mypy duplicate name and ruff lint issues
    
    - Rename second 'vector' variable to 'img_vector' in image embedding loop
    - Combine nested with statements in tests
    - Remove unused result assignments in tests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updates from feedback
    
    * Fix CI failures in embedding usage handling
    
    - Fix Azure AI embedding mypy issues by normalizing vectors to list[float],
      safely accumulating optional usage token fields, and filtering None entries
      before constructing GeneratedEmbeddings
    - Avoid Bandit false positive by initializing usage details as an empty dict
    - Update OpenAI embedding tests to assert canonical usage keys
      (input_token_count/total_token_count)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Support Agent Skills (#4210)
    * Python: Support Agent Skills
    
    Add FileAgentSkillsProvider, a context provider that discovers and exposes
    Agent Skills from filesystem directories following the Agent Skills
    specification (https://agentskills.io/) progressive disclosure pattern:
    advertise, load, read resources.
    
    Changes:
    - FileAgentSkillsProvider - discovers SKILL.md files from configured
      directories, advertises skills via system prompt injection, and provides
      load_skill / read_skill_resource tools for on-demand access.
    - Internal helpers for skill discovery, frontmatter parsing, and secure
      resource reading (path traversal / symlink guards).
    - Unit tests covering discovery, loading, resource reading, and security
      scenarios.
    - Sample (basic_file_skills) demonstrating usage with an expense-report skill.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Move skills sample to samples/02-agents/basic_skills/
    
    Align sample directory name with .NET equivalent (Agent_Step01_BasicSkills).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix code quality checks
    
    * address pr review comment and code quality check issue
    
    * address pr review comments
    
    * move the sample to the skills folder
    
    * update readme
    
    * reame consts and use types for them
    
    * leverage pathlib for working with files
    
    * refactor the test
    
    * supply schema to functions
    
    * update readme
    
    * update sample name
    
    * address pr review comments
    
    * fix failing lint check
    
    * address failing check
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Azure AI Search provider improvements - EmbeddingGenerator, async context manager, KB message handling (#4212)
    * small updates and improvements in the azure AISearch provider
    
    * Fix mypy errors and embedding function test
    
    - Use separate variable for embeddings result to avoid mypy type reassignment error
    - Fix test_vectorized_query_with_embedding_function: use real async function
      instead of AsyncMock which falsely matches SupportsGetEmbeddings protocol
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fixes from feedback
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fixing issue #1366 - Thread corruption when max_iterations is reached. (#4234)
    * Fix thread corruption when max_iterations exhausted (#1366)
    
    When the function invocation loop exhausts max_iterations while the model
    keeps requesting tools, the failsafe code path (calling the model with
    tool_choice='none' and prepending fcc_messages) was unreachable because
    'if response is not None: return response' short-circuited before it.
    
    The fix removes the premature return so the failsafe always runs after
    loop exhaustion, making a final model call with tool_choice='none' to
    produce a clean text answer and prepending accumulated fcc_messages from
    prior iterations. This matches the existing pattern used by the error
    threshold and max_function_calls paths.
    
    Also unskips test_max_iterations_limit and test_streaming_max_iterations_limit
    which were previously skipped with 'needs investigation in unified API'.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add fix report for issue #1366
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix ruff formatting in _tools.py and test_issue_1366_thread_corruption.py
    
    Apply ruff format to fix multi-line string concatenation and function call
    formatting issues flagged by the linter.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add quality review for issue #1366 fix
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove temporary investigation docs.
    
    * Address PR review: explicit enabled check in log condition, clarify mock behavior in test
    
    - Add explicit function_invocation_configuration['enabled'] check to the
      'Maximum iterations reached' log condition in both non-streaming and
      streaming paths, making intent clearer when function invocation is disabled.
    - Add comment in test_thread_safe_after_max_iterations_with_agent explaining
      that the failsafe response (tool_choice='none') is provided automatically
      by the mock client, not from run_responses.
    
    * Blend fix and tests into project without issue-specific callouts
    
    - Remove issue #1366 references from _tools.py comments
    - Move regression tests from standalone test_issue_1366_thread_corruption.py
      into test_function_invocation_logic.py alongside existing max_iterations tests
    - Clean up test docstrings to describe behavior generically
    - Delete the standalone issue-specific test file
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • [BREAKING] Python: Add InvokeFunctionTool action for declarative workflows (#3716)
    * add(declarative): Declarative workflow InvokeFunctionTool feature
    
    * Cleanup
    
    * Address PR feedback
    
    * Remove InvokeTool kind, consolidate to InvokeFunctionTool
    
    * Fix sample locations
    
    * pin azure-ai-projects to 2.0.0b3 due to breaking changes
  • Python: Fix workflow runner concurrent processing (#4143)
    * Fix workflow runner concurrent processing
    
    * Comments 1
    
    * Add test
  • Python: Fix doubled tool_call arguments in MESSAGES_SNAPSHOT when streaming (#4200)
    * fix: prevent doubled tool_call arguments in MESSAGES_SNAPSHOT
    
    When streaming with client-side tools, some providers send a full-
    arguments replay after the streaming deltas complete. The `_emit_tool_call`
    function unconditionally appends every arguments delta to the internal
    `flow.tool_calls_by_id` tracking dictionary via `+=`. When the replay
    contains the exact same complete arguments string that was already
    accumulated from prior deltas, the arguments get doubled (e.g.,
    `{"todoText":"buy groceries"}{"todoText":"buy groceries"}`).
    
    This causes `MESSAGES_SNAPSHOT` events to contain invalid doubled JSON in
    `tool_calls[].function.arguments`, breaking any client or middleware that
    relies on snapshots for state reconstruction.
    
    The fix adds a guard (mirroring the existing duplicate guard in
    `_emit_text`) that detects when the incoming delta exactly equals the
    already-accumulated arguments string, indicating a full-arguments replay
    rather than an incremental delta. In this case the append is skipped,
    preventing the doubling.
    
    The `ToolCallArgsEvent` deltas are still emitted correctly for real-time
    streaming — only the internal snapshot accumulator is guarded.
    
    Fixes #4194
    
    * fix: move duplicate check before event emission + add test
    
    Address Copilot review feedback:
    1. Move duplicate full-arguments replay detection BEFORE emitting
       ToolCallArgsEvent, for consistency with _emit_text() which returns
       early without emitting any events on replay detection.
    2. Add test_emit_tool_call_skips_duplicate_full_arguments_replay() to
       verify the duplicate detection behavior for tool call arguments,
       matching the existing test pattern for text content.
  • Python: updated integration tests and guidance (#4181)
    * updated integration tests and guidance
    
    * fixed merge test
    
    * updated integration tests
    
    * fix: remove duplicate --dist loadfile flag from pytest-xdist config
    
    Only one --dist mode can be active at a time; the second value silently
    overrides the first. Keep --dist worksteal (dynamic load balancing) and
    remove the redundant --dist loadfile from all workflow files and
    pyproject.toml configs.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs: add keep-in-sync notes for merge and integration test workflows
    
    Both python-merge-tests.yml and python-integration-tests.yml share the
    same parallel job structure. Added sync reminders in workflow file
    comments, the python-testing SKILL.md, and CODING_STANDARD.md.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor: remove RUN_INTEGRATION_TESTS flag
    
    Integration test gating now uses two mechanisms:
    - `@pytest.mark.integration` for test selection via `-m` filtering
    - `skip_if_*_disabled` for credential/service availability checks
    
    The RUN_INTEGRATION_TESTS env var was redundant since the marker handles
    selection and the skip decorators already check for actual credentials.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: sync missing env vars from merge-tests to integration-tests
    
    Add OPENAI_EMBEDDINGS_MODEL_ID and AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME
    to python-integration-tests.yml to match python-merge-tests.yml.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: remove remaining RUN_INTEGRATION_TESTS from embedding tests and docs
    
    Missed test_openai_embedding_client.py and vector-stores README in the
    earlier cleanup.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * set functions tests to 3.10
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: feat(python): Add embedding abstractions and OpenAI implementation (Phase 1) (#4153)
    * feat(python): Add embedding abstractions and OpenAI implementation (Phase 1)
    
    This PR contains two parts:
    
    1. **Overall migration plan** for porting vector stores and embeddings from
       Semantic Kernel to Agent Framework (docs/features/vector-stores-and-embeddings/README.md)
       covering all 10 phases from core abstractions through connectors and TextSearch.
    
    2. **Phase 1 implementation** — core embedding abstractions and OpenAI/Azure OpenAI
       embedding clients:
    
       Core types (_types.py):
       - EmbeddingGenerationOptions TypedDict (total=False)
       - Embedding[EmbeddingT] generic class with model_id, dimensions, created_at
       - GeneratedEmbeddings[EmbeddingT, EmbeddingOptionsT] list container with options, usage
       - EmbeddingInputT (default str) and EmbeddingT (default list[float]) TypeVars
    
       Protocol + base class (_clients.py):
       - SupportsGetEmbeddings protocol — Generic[EmbeddingInputT, EmbeddingT, OptionsContraT]
       - BaseEmbeddingClient ABC — Generic[EmbeddingInputT, EmbeddingT, OptionsCoT]
    
       Telemetry (observability.py):
       - EmbeddingTelemetryLayer with gen_ai.operation.name = "embeddings"
    
       OpenAI implementation (openai/_embedding_client.py):
       - RawOpenAIEmbeddingClient, OpenAIEmbeddingClient, OpenAIEmbeddingOptions
       - Uses _ensure_client() factory pattern
    
       Azure OpenAI implementation (azure/_embedding_client.py):
       - AzureOpenAIEmbeddingClient following AzureOpenAIChatClient pattern
       - Supports API key, Entra ID credentials, env var configuration
    
       Tests:
       - 47 unit tests for types, protocol, base class, OpenAI, and Azure clients
       - 6 integration tests (gated behind RUN_INTEGRATION_TESTS + credentials)
    
       Samples:
       - samples/02-agents/embeddings/openai_embeddings.py
       - samples/02-agents/embeddings/azure_openai_embeddings.py
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: Add AzureOpenAIEmbeddingClient to azure __init__.pyi stub
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * ci: Add embedding env vars to Python integration tests
    
    Map OPENAI_EMBEDDING_MODEL_ID and AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME
    from GitHub vars to the integration test environment.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: Handle base64 encoding_format in OpenAI embedding client
    
    When encoding_format='base64' is used, the OpenAI API returns base64-encoded
    floats instead of a JSON array. Decode these automatically to list[float]
    so the return type stays consistent regardless of encoding format.
    
    Also adds a unit test for base64 decoding and fixes minor docstring/import issues.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: Only record INPUT_TOKENS for embedding telemetry
    
    Embeddings have no output/completion tokens. Remove OUTPUT_TOKENS recording
    which was double-counting prompt_tokens via the total_tokens fallback.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: Resolve mypy variance error and lint warning
    
    Use contravariant/covariant TypeVars for SupportsGetEmbeddings Protocol.
    Combine nested if into single statement in telemetry layer.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: Make EmbeddingCoT invariant for mypy compatibility
    
    GeneratedEmbeddings is invariant in its type param, so the Protocol
    TypeVar cannot be covariant.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: Address PR review - empty values guard, service_url for telemetry
    
    - Add early return for empty values in get_embeddings to avoid unnecessary API calls
    - Add service_url() method to RawOpenAIEmbeddingClient for proper telemetry endpoint reporting
    - Add test for empty values behavior
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Fix OpenAI chat client compatibility with third-party endpoints and OTel 0.4.14 (#4161)
    
    * Fix system message content sent as list instead of string
    
    Some OpenAI-compatible endpoints (e.g. NVIDIA NIM) reject system messages
    when content is a list of content parts. This change flattens system and
    developer message content to a plain string in the Chat Completions client.
    
    Fixes https://github.com/microsoft/agent-framework/issues/1407
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix compatibility with opentelemetry-semantic-conventions-ai 0.4.14
    
    Version 0.4.14 removed several LLM_* attributes from SpanAttributes
    (LLM_SYSTEM, LLM_REQUEST_MODEL, LLM_RESPONSE_MODEL, LLM_REQUEST_MAX_TOKENS,
    LLM_REQUEST_TEMPERATURE, LLM_REQUEST_TOP_P, LLM_TOKEN_TYPE).
    
    Move these to the OtelAttr enum with their well-known gen_ai.* string values
    and update all references in observability.py and tests.
    
    Fixes https://github.com/microsoft/agent-framework/issues/4160
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Flatten text-only message content to string for all roles
    
    Extend the system/developer fix to all message roles. Text-only content
    lists are now post-processed into plain strings, while multimodal content
    (text + images/audio) remains as a list. This fixes compatibility with
    OpenAI-like endpoints that cannot deserialize list content (e.g. Foundry
    Local's Neutron backend).
    
    Partially fixes https://github.com/microsoft/agent-framework/issues/4084
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix streaming text lost when usage data in same chunk
    
    Some providers (e.g. Gemini) include both usage data and text content
    in the same streaming chunk. The early return on chunk.usage caused
    text and tool call parsing to be skipped entirely. Remove the early
    return and process usage alongside text/tool calls.
    
    Fixes https://github.com/microsoft/agent-framework/issues/3434
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix mypy errors in _chat_client.py
    
    Rename shadowed variable 'args' in system/developer branch to 'sys_args'
    and rename loop variable 'content' to 'msg_content' to avoid type conflict.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * reorder imports
    
    * fix: Use OtelAttr.REQUEST_MODEL instead of removed SpanAttributes.LLM_REQUEST_MODEL
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs: Add score_threshold to vector store plan
    
    Reference SK .NET PR #13501 for score threshold filtering semantics.
    Include score_threshold in SearchOptions from Phase 3.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs: Add reference to roji's SK .NET MEVD work for SQL connectors
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: Clear env vars in construction tests to avoid CI leakage
    
    Tests for missing API key / model ID now use monkeypatch.delenv to ensure
    env vars from the integration test environment don't prevent the expected
    ValueError from being raised.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add Foundry Memory Context Provider (#3943)
    * Initial plan
    
    * Add FoundryMemoryProvider and tests
    
    Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com>
    
    * Add sample and documentation for FoundryMemoryProvider
    
    Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com>
    
    * Address code review feedback for FoundryMemoryProvider
    
    Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com>
    
    * Address PR review comments: Add DEFAULT_SOURCE_ID, use logging.getLogger, move state to session.state
    
    Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com>
    
    * Fix Foundry memory ItemParam usage and exports
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Refactor provider hook state and standardize source IDs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Support endpoint-based Foundry memory init
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated implementation and sample
    
    * updated code and samples
    
    * Fix foundry memory provider tests: mock structure and field names
    
    - Use Mock objects with memory_item.content for memory mocks
    - Assert 'content' instead of 'text' on SDK message items
    - Update exception types from ServiceInitializationError to ValueError
    - Remove unused ServiceInitializationError import
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix mypy errors in foundry memory provider
    
    Add type: ignore[arg-type] for scope (str | None vs str) and items
    (list variance) passed to Azure SDK methods.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix import
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com>
    Co-authored-by: eavanvalkenburg <github@vanvalkenburg.eu>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add CreateConversationExecutor, fix input routing, remove unused handler layer (#4159)
    * Fixed declarative deep research sample
    
    * Small fix
    
    * Resolved comment
    
    * Add CreateConversationExecutor, fix input routing, remove unused handler layer
    
    * Address Copilot feedback
    
    * Fix System.ConversationId
    
    ---------
    
    Co-authored-by: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com>
  • Python: Enhance Azure AI Search Citations with Document URLs in Foundry V2 (#4028)
    * Python: Enhance Azure AI Search citations with document URLs in Foundry V2 (Responses API)
    
    Override _parse_response_from_openai and _parse_chunk_from_openai in
    RawAzureAIClient to extract get_urls from azure_ai_search_call_output
    items and enrich url_citation annotations with document-specific URLs.
    
    - Non-streaming: first pass collects get_urls, post-processes annotations
    - Streaming: captures search output state, enriches url_citation events
      (also handles url_citation annotation type not handled by base class)
    - Updated V2 sample to demonstrate citation URL extraction
    - Added 14 unit tests covering extraction, enrichment, and edge cases
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor: rework search citation enrichment to override _inner_get_response
    
    - Remove all direct openai/pydantic imports from _client.py
    - Override _inner_get_response instead of _parse_response_from_openai/_parse_chunk_from_openai
    - Use closure-local state for streaming instead of instance-level _streaming_search_get_urls
    - Add _build_url_citation_content helper for streaming url_citation handling
    - Fix mypy errors by using str(value or '') for Annotation TypedDict fields
    - Fix docstring to say 'citation' instead of 'url_citation'
    - Update tests to match new approach
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: handle streaming search citations from output_item.done events
    
    The azure_ai_search_call_output item only has populated output data
    (including get_urls) in the response.output_item.done event, not in
    the response.output_item.added event. Also removed the search_get_urls
    guard on url_citation handling so annotations are always produced even
    if get_urls haven't been captured yet.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * addressed comments
    
    * refactor: address PR review - eliminate type: ignore[assignment] pattern
    
    Call super()._inner_get_response() independently in each branch instead
    of once at the top with union type reassignment. Non-streaming uses
    two-arg super() in the closure; streaming uses cast() for type narrowing.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor: remove defensive patterns per PR review
    
    - Replace all getattr() with direct attribute access
    - Remove cast() for streaming branch, use type: ignore[assignment]
    - Simplify _build_url_citation_content to use dict access directly
    - Simplify _extract_azure_search_urls to use item.type/item.output
    - Handle empty list output from streaming 'added' events
    - Update tests to match actual runtime types (objects, not dicts)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * mypy fix
    
    * small fixes
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>