Commit Graph

350 Commits

  • 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>
  • 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>
  • Python: Aggregate token usage across tool-call loop iterations in invoke_agent span (#4739)
    * Fix invoke_agent span to aggregate token usage across LLM calls (#4062)
    
    The FunctionInvocationLayer._get_response() loop was overwriting the
    response on each iteration, so usage_details only reflected the last
    chat completion call. Now tracks aggregated_usage across all iterations
    using add_usage_details() and sets it on the returned response.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Remove reproduction report artifact
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Apply pre-commit auto-fixes
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Simplify Python Poe tasks and unify package selectors (#4722)
    * updated automation tasks and commands, with alias for the time being
    
    * Restore aggregate test exclusions
    
    Preserve the legacy all-tests scope for test --all by excluding lab and devui from the default aggregate sweep, while still allowing explicit package selection. Also ignore hidden/generated test directories such as .mypy_cache during aggregate discovery.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated versions in pre-commit
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix ENABLE_SENSITIVE_DATA env var ignored when set after module import (#4743)
    * Python: Re-read env vars in configure_otel_providers and enable_instrumentation (#4119)
    
    Fix ENABLE_SENSITIVE_DATA and VS_CODE_EXTENSION_PORT env vars being ignored
    when load_dotenv() runs after module import. The module-level
    OBSERVABILITY_SETTINGS singleton cached env state at import time, and
    configure_otel_providers() / enable_instrumentation() never re-read from
    os.environ when parameters were None.
    
    Both functions now construct a fresh ObservabilitySettings() to pick up
    current env vars when explicit parameters are not provided, matching the
    existing behavior of the env_file_path branch.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback for #4119: avoid throwaway ObservabilitySettings
    
    - Add _read_bool_env/_read_int_env helpers to read env vars without
      constructing a full ObservabilitySettings (which calls create_resource())
    - Replace ObservabilitySettings() in enable_instrumentation() and
      configure_otel_providers() else-branch with direct env reads
    - Add enable_console_exporters parameter to configure_otel_providers()
      for override parity with enable_sensitive_data and vs_code_extension_port
    - Propagate _resource and _executed_setup in the non-env_file_path branch
    - Make existing tests hermetic (clear VS_CODE_EXTENSION_PORT and
      ENABLE_CONSOLE_EXPORTERS env vars)
    - Add tests: enable_console_exporters env refresh, explicit param overrides
      for both enable_instrumentation() and configure_otel_providers()
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address remaining review feedback for #4119
    
    - Refresh enable_console_exporters in enable_instrumentation() for
      consistency with configure_otel_providers(), so env var changes
      after import are picked up by both public API functions
    - Make test_configure_otel_providers_reads_env_vs_code_port hermetic
      by clearing ENABLE_CONSOLE_EXPORTERS from the environment
    - Add test_enable_instrumentation_reads_env_console_exporters to
      cover the new refresh behavior
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove unconditional enable_console_exporters overwrite from enable_instrumentation() (#4119)
    
    enable_instrumentation() is documented as not configuring exporters, so
    managing enable_console_exporters there was a leaky abstraction. The
    unconditional _read_bool_env call silently reset the value to False when
    ENABLE_CONSOLE_EXPORTERS was absent from env, clobbering any value
    previously set by configure_otel_providers(enable_console_exporters=True).
    
    - Remove the unconditional overwrite line from enable_instrumentation()
    - Replace test_enable_instrumentation_reads_env_console_exporters with
      test_enable_instrumentation_does_not_touch_console_exporters
    - Add regression test: enable_instrumentation() does not clobber a
      previously configured enable_console_exporters value
    - Add test: explicit enable_sensitive_data param still leaves
      enable_console_exporters untouched
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix missing methods on the Content class in durable tasks (#4738)
    * Fix Content serialization in DurableAgentStateUnknownContent (#4719)
    
    DurableAgentStateUnknownContent.from_unknown_content() stored raw Content
    objects without converting them to dicts, causing json.dumps to fail in
    Azure Durable Functions' entity state serialization. This affected content
    types not explicitly handled (e.g., mcp_server_tool_call/result).
    
    The fix converts Content objects to dicts via to_dict() when storing in
    DurableAgentStateUnknownContent, and restores them via Content.from_dict()
    in to_ai_content().
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add to_json and from_json methods to Content class (#4719)
    
    Add to_json() and from_json() methods to the Content class to match the
    serialization interface provided by SerializationMixin on other model classes.
    Also fix pre-existing pyright type errors in durabletask's
    DurableAgentStateUnknownContent.to_ai_content().
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review: add type guard, remove to_json, add fallback, and tests
    
    - Remove Content.to_json() per reviewer request (comment 3)
    - Add type guard in Content.from_json() for non-dict JSON (comments 1, 4)
    - Wrap json.JSONDecodeError as ValueError for consistent exception contract
    - Add try/except fallback in to_ai_content() for invalid Content dicts (comment 5)
    - Add test_content_to_dict_exclude_none and test_content_to_dict_exclude_fields (comment 2)
    - Add test_unknown_content_to_ai_content_fallback_on_invalid_type_dict (comment 5)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    * Address review feedback for #4719: review comment fixes
    
    * Remove Content.from_json, move logic to consuming code (#4719)
    
    Remove the from_json convenience method from Content class per review
    feedback. This is the same trivial json.loads + from_dict wrapper as
    to_json which was already removed. Consumers should call json.loads
    and Content.from_dict directly.
    
    Update tests to use Content.from_dict(json.loads(...)) pattern and
    remove from_json-specific error handling tests (those errors are
    already covered by json.loads and Content.from_dict).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Reduce Azure chat client import overhead (#4744)
    * Reduce Azure chat client import overhead
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix Azure chat client type annotations and add _parse_text_from_openai tests
    
    - Move Choice and ChunkChoice imports under TYPE_CHECKING to avoid
      runtime import cost (from __future__ annotations is already present)
    - Restore proper typed signature (Choice | ChunkChoice) instead of Any
    - Add direct unit tests for _parse_text_from_openai covering:
      - Choice with message content
      - ChunkChoice with delta content
      - Refusal branch for both Choice and ChunkChoice
      - No content/no refusal returning None
      - None delta (async content filtering) returning None
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Copilot <copilot@github.com>
  • Python: fix 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>
  • Python: normalize empty MCP tool output to null (#4683)
    * Python: normalize empty MCP tool output to null
    
    * Python: hardcode null for empty MCP output
  • Python: chore(python): improve dependency range automation (#4343)
    * chore(python): improve dependency range automation
    
    - tighten dependency bounds and coding standards guidance\n- add dependency range validation workflow, reporting, and issue automation\n- update related tests and dependency pins for compatibility
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated text and pyarrow
    
    * new lock
    
    * fixed workflow
    
    * updated deps
    
    * fix tiktoken
    
    * chore(python): refine dependency validation workflows
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(python): add high-level dependency validation comments
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * WIP
    
    * added additional comments and excludes
    
    * added dev dependency handling and workflow and updates to package ranges
    
    * added readme and simplified commands
    
    * fix markers
    
    * chore(python): address dependency review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Tighten dependency bounds, remove stale overrides, restore Python 3.10 support
    
    - Apply dependency bound policy across all packages: stable >=1.0 deps use
      >=floor,<next_major; pre-1.0/prerelease deps use validated hard-bounded ranges
    - Remove stale root tool.uv.override-dependencies (uvicorn, websockets, grpcio)
    - Lower github_copilot requires-python to >=3.10 with github-copilot-sdk gated
      behind python_version >= 3.11 marker; import raises ImportError on 3.10
    - Skip github_copilot pyright/mypy/test tasks on Python <3.11
    - Use version-conditional pyrightconfig for samples on Python 3.10
    - Add compatibility fix in core responses client for older openai typed dicts
    - Normalize uv.lock prerelease mode and refresh dev dependencies
    - Update CODING_STANDARD.md, DEV_SETUP.md, and package management skill docs
    
    Closes #902
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * small tweaks
    
    * add note in workflow
    
    * fix workflows and several versions
    
    * fix duplicate
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • [BREAKING] Python: clean up kwargs across agents, chat clients, tools, and sessions (#4581)
    * Python: clean up kwargs across agents, chat clients, tools, and sessions (#3642)
    
    Audit and refactor public **kwargs usage across core agents, chat clients,
    tools, sessions, and provider packages per the migration strategy codified
    in CODING_STANDARD.md.
    
    Key changes:
    - Add explicit runtime buckets: function_invocation_kwargs and client_kwargs
      on RawAgent.run() and chat client get_response() layers.
    - Refactor FunctionTool to prefer explicit ctx: FunctionInvocationContext
      injection; legacy **kwargs tools still work via _forward_runtime_kwargs.
    - Refactor Agent.as_tool() to use direct JSON schema, always-streaming
      wrapper, approval_mode parameter, and UserInputRequiredException
      propagation (integrates PR #4568 behavior).
    - Remove implicit session bleeding into FunctionInvocationContext; tools
      that need a session must receive it via function_invocation_kwargs.
    - Lower chat-client layers after FunctionInvocationLayer accept only
      compatibility **kwargs (client_kwargs flattened, function_invocation_kwargs
      ignored).
    - Add layered docstring composition from Raw... implementations via
      _docstrings.py helper.
    - Clean up provider constructors to use explicit additional_properties.
    - Deprecation warnings on legacy direct kwargs paths.
    - Update samples, tests, and typing across all 23 packages.
    
    Resolves #3642
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * clarified docstring
    
    * feedback fixes
    
    * Add unit tests for _docstrings.py build/apply helpers
    
    Tests cover: no docstring source, no extra kwargs, appending to existing
    Keyword Args section, inserting after Args, inserting in plain docstrings,
    multiline descriptions, ordering, and apply_layered_docstring.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add test for propagate_session TypeError on non-AgentSession values
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add tests for multi-content and empty UserInputRequiredException propagation
    
    Cover the branching logic in _try_execute_function_calls for:
    - Multiple user_input_request items in a single exception (extra_user_input_contents path)
    - Empty contents list (fallback function_result path)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add tests for DurableAIAgent.get_session forwarding service_session_id
    
    Verifies get_session correctly forwards service_session_id and session_id
    to the executor's get_new_session, replacing the removed kwargs test.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Simplify ag-ui test stub to read session from client_kwargs only
    
    Remove dual-mode detection (client_kwargs vs raw kwargs fallback) from
    the test mock. Session is now read exclusively from client_kwargs,
    matching the settled public calling convention.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated create and get sessions in durable
    
    * fixed docstrings
    
    * fix test
    
    * updated session handling
    
    * updated from main
    
    * updated tests
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix type hint for Case and Default (#3985)
    * Fix type hint for `Case` and `Default`
    
    * Add test
    
    ---------
    
    Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
  • Python: Unify tool results as Content items with rich content support (#4331)
    * feat(python): allow @tool functions to return rich content (images, audio)
    
    Add support for tool functions to return Content objects that the model can perceive natively. Closes #4272
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Anthropic logging + mypy fix
    
    * Address PR review: fix MCP ordering, fold helper into from_function_result, fix Chat client
    
    - Preserve original content order in MCP tool results instead of text-first
    - Move _build_function_result logic into Content.from_function_result()
    - Chat Completions: inject user message for rich items (API only supports string tool content)
    - Update tests for ordering and new from_function_result behavior
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Use native Responses API multi-part output, warn+omit for Chat client
    
    - Responses client: put rich items directly in function_call_output's
      output field as list (native API support) instead of user message injection
    - Chat client: warn and omit rich items (API doesn't support multi-part
      tool results), matching Ollama/Bedrock pattern
    - Unify test image: use sample_image.jpg across all integration tests
    - Add Azure OpenAI Responses integration test
    - Assert model describes house image to verify perception
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix lint: remove print statement, wrap long line
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback: bug fixes, single-pass MCP, unit tests
    
    - Add isinstance guard in from_function_result for non-Content lists
    - Fix Anthropic empty tool_content fallback to string result
    - Fix Content(type='text', text=None) edge case in parse_result
    - Rewrite MCP _parse_tool_result_from_mcp as single-pass (no index counters)
    - Add Anthropic unit tests: data image, uri image, unsupported media, all-unsupported
    - Add OpenAI Chat unit test: rich items warning and omission
    - Add OpenAI Responses unit tests: function_result with/without items
    - Add test_types tests: only-rich-items list, non-Content list fallback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pyright errors: add type ignore comments for Any list iteration
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix mypy/pyright: ensure ToolExecutionException receives str
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix lint: remove duplicate test_prepare_options_excludes_conversation_id
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor: unify all tool results into Content items
    
    * addressed copilot comments
    
    * pyright fix
    
    * small fix
    
    * comments
    
    * fix: address Copilot review - warnings, blob safety, dedup
    
    - Add warning logs when rich content is dropped in Claude agent and
      MCP server handlers (matching Chat/Bedrock/Ollama pattern)
    - Defensive blob URI construction: wrap plain base64 in data: prefix
    - Simplify Chat client _prepare_content_for_openai to use content.result
    - Simplify Responses client text-only path, remove redundant nesting
    - Add test for plain base64 blob without data: prefix
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix token double-counting in compaction and address review comments
    
    - Exclude items from _serialize_content() to prevent double-counting
      tokens when items mirrors result in function_result content
    - Add rich content warning in GitHub Copilot agent tool handler
    - Replace raw Content debug log with concise item count/type summary
    - Update stale test comments about FunctionTool.invoke return type
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix missing status input for OpenAI responses API (#4626)
    * Fix missing status input for OpenAI responses API
    
    * Fix mypy
    
    * Address comments
    
    * Remove raw_rep restore
    
    * Do not set status if it's None
  • Python: Implement annotation-based context compaction (#4469)
    * Implement annotation-based context compaction
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Handle missing compaction attributes in BaseChatClient
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CI typing and bandit issues
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Optimize incremental compaction annotation pass
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refinement
    
    * Python: add ToolResultCompactionStrategy and CompactionProvider
    
    Add ToolResultCompactionStrategy that collapses older tool-call groups
    into short summary messages (e.g. [Tool calls: get_weather]) while
    keeping the most recent groups verbatim. This mirrors the .NET
    ToolResultCompactionStrategy from PR #4533.
    
    Add CompactionProvider as a context-provider that auto-applies compaction
    before each agent turn and stores compacted history in session state
    after each turn.
    
    Includes tests and samples for both features.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refinement and alignment with dotnet PR
    
    * updated tool result compaction
    
    * updated tool result compaction
    
    * Python: add ToolResultCompactionStrategy, CompactionProvider, and skip_excluded
    
    - ToolResultCompactionStrategy collapses older tool-call groups into
      [Tool results: func_name: result] summaries with bidirectional tracing
      (same pattern as SummarizationStrategy).
    - CompactionProvider as BaseContextProvider with separate before_strategy
      and after_strategy parameters. before_strategy compacts loaded context;
      after_strategy compacts stored history via history_source_id.
    - InMemoryHistoryProvider gains skip_excluded flag to filter out messages
      marked as excluded by compaction strategies.
    - Tests, samples, and exports updated.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fixed checks
    
    * fix mypy
    
    * Fix: ensure summary messages from both strategies get full compaction annotations
    
    SummarizationStrategy was not calling annotate_message_groups after
    inserting its summary message, so the summary lacked core group
    annotations (id, kind, index, has_reasoning, _excluded). Added the
    missing call. ToolResultCompactionStrategy already had it.
    
    Added tests verifying both strategies produce fully annotated summaries.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated propagation
    
    * fix mypy
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Support skill scripts execution (#4558)
    * support skill scripts execution
    
    * fix mixed line endings
    
    * address comments and fix syntax issues
    
    * use few try/except instead of one
    
    * change samples
    
    * validate either script path or script resource is set not both
    
    * fix: separate LLM args from runtime kwargs in skill script execution
    
    * address pr review comments
    
    * address PR review comments
    
    * Update python/packages/core/agent_framework/_skills.py
    
    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
    
    * Update python/packages/core/agent_framework/_skills.py
    
    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
    
    * Update python/packages/core/agent_framework/_skills.py
    
    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
    
    * 1. Fixing the caching bug where parameters_schema would re-inspect on every call when the result was None
       2. Updating the arguments tool description to be more generic (not CLI-specific)
    
    * fix failing tests
    
    * address pr review comments
    
    * address pr review comments
    
    * allow resource function returning any instead of sting
    
    * address PR review comments
    
    ---------
    
    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
  • Python: Fix executor_completed event with non-copyable raw_representation in mixed workflows (#4493)
    * Python: Fix `executor_completed` event with non-copyable raw_representation in mixed workflows
    
    Fixes #4455
    
    * fix(#4455): use class-level sets for deepcopy field exclusion
    
    - SerializationMixin.__deepcopy__: check type(self).DEFAULT_EXCLUDE
      instead of hardcoding 'raw_representation'
    - Content.__deepcopy__: add _SHALLOW_COPY_FIELDS class variable and
      check against it instead of hardcoding
    - Fix tautological assertion in test (was always True)
    - Add second excluded field to test to verify DEFAULT_EXCLUDE is
      respected generically
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Decouple __deepcopy__ from DEFAULT_EXCLUDE in SerializationMixin (#4455)
    
    Introduce _SHALLOW_COPY_FIELDS class variable in SerializationMixin to
    separate deep-copy semantics from serialization semantics. Previously,
    __deepcopy__ used DEFAULT_EXCLUDE to decide which fields to shallow-copy,
    conflating 'not serialized' with 'not safe to deep-copy'. A field added
    to DEFAULT_EXCLUDE purely for serialization (e.g. additional_properties)
    would be silently shared between original and copy.
    
    - Add _SHALLOW_COPY_FIELDS (default {'raw_representation'}) to
      SerializationMixin, matching the pattern already used by Content
    - Update __deepcopy__ to read from _SHALLOW_COPY_FIELDS instead of
      DEFAULT_EXCLUDE
    - Add test verifying DEFAULT_EXCLUDE fields are deep-copied unless
      also in _SHALLOW_COPY_FIELDS
    - Add test for Content._SHALLOW_COPY_FIELDS identity preservation
    - Add test for ChatResponse deep-copying additional_properties
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add test for _SHALLOW_COPY_FIELDS and DEFAULT_EXCLUDE independence
    
    Add test_deepcopy_shallow_copy_fields_override_default_exclude to verify
    that a field in both DEFAULT_EXCLUDE and _SHALLOW_COPY_FIELDS is
    shallow-copied (controlled by _SHALLOW_COPY_FIELDS), while a field in
    DEFAULT_EXCLUDE only is still deep-copied. This addresses review comment
    #11 ensuring the two class variables control independent concerns.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove unnecessary local variable in __deepcopy__
    
    Inline cls._SHALLOW_COPY_FIELDS directly in the loop check instead of
    assigning to a local variable first, per review feedback.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply pre-commit auto-fixes
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix store=False not overriding client default (#4569)
    * Fix store=False not overriding client default
    
    * Address comments
    
    * Fix unit tests
    
    * Fix integration tests
    
    * Fix tests
  • Auto-finalize ResponseStream on iteration completion (#4478)
    * Add multi-turn streaming sample and rename multi-turn samples
    
    - Rename 03_multi_turn.py to 03a_multi_turn.py
    - Add 03b_multi_turn_streaming.py showing streaming with session history
    - The new sample demonstrates calling get_final_response() after
      iterating the stream to persist conversation history
    - Update READMEs to reflect the new file names
    
    Closes #4447
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Auto-finalize ResponseStream on iteration completion
    
    When a ResponseStream is fully consumed via async iteration,
    automatically trigger finalization (finalizer + result hooks).
    This ensures session history is persisted in streaming multi-turn
    conversations without requiring an explicit get_final_response() call.
    
    - Add auto-finalize call in __anext__ on StopAsyncIteration
    - Guard inner stream finalization to prevent double-execution
    - Re-check _finalized after iteration in get_final_response()
    - Add tests for auto-finalization and streaming session history
    - Revert sample file renames from previous commit
    
    Closes #4447
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * README fix
    
    * Fix SIM102 lint: combine nested if statements
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Exclude conversation_id from chat completions API options (#4517)
    * Python: Exclude conversation_id from chat completions options (#4315)
    
    When a session with service_session_id is passed to an agent using the
    Chat Completions client, conversation_id leaked through _prepare_options()
    into AsyncCompletions.create(), causing an 'unexpected keyword argument'
    error. The Responses client already excluded conversation_id but the Chat
    Completions client did not.
    
    Added conversation_id to the exclusion set in _prepare_options().
    
    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>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix conversation-id propagation when chat_options is a dict (#4340)
    * Fix #4305: Handle dict chat_options in _update_conversation_id
    
    _update_conversation_id assumed chat_options had attribute access, but
    ChatOptions is a TypedDict (dict). When a dict was passed, setting
    .conversation_id raised AttributeError. Now checks isinstance(dict) and
    uses key access for dicts, falling back to attribute access for objects.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR feedback: use Mapping ABC and add missing tests (#4305)
    
    - Use collections.abc.Mapping instead of dict for isinstance check in
      _update_conversation_id, making it more robust for non-dict mapping types.
    - Add test for object-style chat_options with optional options dict parameter.
    - Add test verifying existing conversation_id gets overwritten (idempotent).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove unnecessary Mapping check in _update_conversation_id (#4305)
    
    chat_options is always a dict, so the isinstance(chat_opts, Mapping)
    check and the else branch for attribute-style access are dead code.
    Simplify to direct dict key assignment and remove object-style tests.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: [Breaking] Upgrade to azure-ai-projects 2.0+ (#4536)
    * Prepare azure-ai-projects 2.0 GA compatibility
    
    Add allow_preview support for internal AIProjectClient creation, keep backward compatibility for renamed SDK model classes, and align Azure AI/core paths and tests for GA validation workflows.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * upgrade to ai-project==2.0.0
    
    * Python: remove azure-ai-projects keyword-guard paths
    
    Assume azure-ai-projects 2.0+ in Azure AI client/provider/responses code paths by removing _supports_keyword_argument gating and related fallback branching.
    
    Also fix pyright typing in FoundryMemoryProvider memory store calls by using ResponseInputItemParam-typed items.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * check fixes
    
    * Python: remove unsupported foundry_features option
    
    Drop foundry_features from Azure AI client and provider surfaces because azure-ai-projects 2.0.0 does not expose that create_version parameter.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: add allow_preview to Foundry memory provider
    
    Propagate allow_preview when FoundryMemoryProvider constructs an AIProjectClient and update tests accordingly.
    
    Also finish wiring allow_preview through AzureAIClient-facing surfaces and related docs.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * aligning docstrings
    
    * udpated lock
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • [BREAKING] Python: Update github-copilot-sdk integration to use ToolInvocation/ToolResult types (#4551)
    * Update github_copilot package for github-copilot-sdk>=0.1.32 (#4549)
    
    - Update requires-python from >=3.10 to >=3.11
    - Remove Python 3.10 classifier
    - Update mypy python_version to 3.11
    - Update dependency to github-copilot-sdk>=0.1.32
    - Fix ToolResult API: use snake_case kwargs (text_result_for_llm,
      result_type) instead of camelCase (textResultForLlm, resultType)
    - Update test assertions to use attribute access on ToolResult
    - Add ToolResult type assertions to tool handler tests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix tests to use ToolInvocation dataclass instead of plain dict (#4549)
    
    Update test_github_copilot_agent.py to pass ToolInvocation objects to tool
    handlers instead of plain dicts, matching the github-copilot-sdk>=0.1.32 API
    where ToolInvocation is a dataclass with an .arguments attribute.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add regression tests for ToolInvocation contract (#4549)
    
    Add tests to lock in the new ToolInvocation-based calling convention:
    - test_tool_handler_rejects_raw_dict_invocation: verifies passing a raw
      dict (old calling convention) raises TypeError/AttributeError
    - test_tool_handler_with_empty_arguments: verifies ToolInvocation with
      empty arguments works correctly for no-arg tools
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Revert requires-python to >=3.10 to avoid breaking CI (#4549)
    
    The repo CI runs with Python 3.10 (uv sync --all-packages) and all other
    packages require >=3.10. Raising this package to >=3.11 would break the
    shared install flow. The SDK dependency version constraint (>=0.1.32) will
    enforce any Python version requirement from the SDK itself.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix min Python version for github_copilot package to >=3.11
    
    github-copilot-sdk>=0.1.32 requires Python>=3.11, which conflicts
    with the package's declared >=3.10 minimum, breaking uv sync.
    
    * Bump py version for GH workflows to 3.11, exclude GHCP sdk from 3.10 items
    
    * Fix uv command
    
    * Fixes
    
    * Update samples
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Propagated MCP isError flag through function middleware pipeline (#4511)
    * Propagated MCP isError flag through function middleware pipeline
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Small update
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CI
    
    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: 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: 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: 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: 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: 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: 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>