Commit Graph

110 Commits

  • Python: feat(python): Add MCP client OTel spans per GenAI semantic conventions (#6349)
    * feat(python): Add MCP client OTel spans per GenAI semantic conventions
    
    Implement MCP client spans per the OTel GenAI Semantic Conventions for MCP
    (https://opentelemetry.io/docs/specs/semconv/gen-ai/mcp/#client).
    
    Operations instrumented:
    - initialize: CLIENT span capturing MCP session setup
    - tools/list: CLIENT span for tool listing (per-page)
    - prompts/list: CLIENT span for prompt listing (per-page)
    - tools/call: CLIENT span (nested under execute_tool when called via FunctionTool)
    - prompts/get: CLIENT span
    
    Span attributes follow the MCP semantic conventions:
    - Required: mcp.method.name
    - Conditional: error.type, gen_ai.tool.name, gen_ai.prompt.name
    - Recommended: gen_ai.operation.name, mcp.protocol.version, mcp.session.id,
      network.transport, server.address, server.port
    
    Transport-specific attributes per subclass:
    - MCPStdioTool: network.transport=pipe
    - MCPStreamableHTTPTool: network.transport=tcp, network.protocol.name=http
    - MCPWebsocketTool: network.transport=tcp, network.protocol.name=websocket
    
    All span creation gated behind OBSERVABILITY_SETTINGS.ENABLED.
    
    Closes #3624
    Closes #4697
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor: simplify MCP spans — remove enrichment logic and protocol version caching
    
    - Always create nested CLIENT spans for tools/call instead of enriching
      the parent execute_tool span
    - Remove _ACTIVE_TOOL_EXECUTION_SPAN contextvar (no longer needed)
    - Remove enrich_span_with_mcp_attributes() helper
    - Remove _otel_error_type preservation in FunctionTool.invoke()
    - Remove _mcp_protocol_version instance variable; protocol version is
      only set on the initialize span where it is available
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Refine copilot solution
    
    * fix: enable automatic exception recording on MCP spans
    
    Remove record_exception=False and set_status_on_exception=False from
    create_mcp_client_span. Let OTel handle exception recording and status
    setting automatically. The manual set_mcp_span_error calls for tools/call
    still correctly set error.type (which OTel's automatic handling doesn't
    touch), so tool_error is preserved.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Reduce number of lines
    
    * Add comment to sample
    
    * test: address PR review comments on MCP observability tests
    
    - Fix initialize test to call mocked session.initialize() and read
      protocolVersion from the result instead of hardcoding it
    - Add tools/call McpError error-path test
    - Add prompts/get McpError error-path test
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix export error
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: MCP long-running task support in Python (#6319)
    * MCP long-running task support in Python
    
    * Fix pyupgrade and AGENTS.md reconnect description
    
    - pyupgrade: drop forward-reference string annotations in _mcp.py (Python 3.10+ resolves them natively now that MCPTaskOptions is defined before use).
    
    - AGENTS.md: align reconnect description with current behavior. Phase 1 (initial tools/call) does NOT retry on connection loss; raises 'connection lost; task state unknown' instead, so a server that accepted the request but lost the response cannot start the operation twice. Phase 2 (tasks/get / tasks/result) still reconnects once against the same task_id.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix bandit nosec marker for CI pipeline
    
    * Address PR feedbacks
    
    * Clarifiied comments and addressed more PR feedbacks.
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: [BREAKING] Upgrade github-copilot-sdk to v1.0.0 (stable) (#6292)
    * Python: Upgrade github-copilot-sdk to v1.0.0 (stable)
    
    Upgrade agent-framework-github-copilot from github-copilot-sdk 1.0.0b2 to the
    stable 1.0.0 release, adapting to all breaking API changes.
    
    Source changes (_agent.py):
    - SubprocessConfig removed: use RuntimeConnection.for_stdio(path=...) +
      CopilotClient kwargs (connection, log_level, base_directory)
    - Import paths: copilot.generated.session_events -> copilot.session_events
    - Settings: copilot_home -> base_directory (env GITHUB_COPILOT_BASE_DIRECTORY)
    - Default deny handler: PermissionDecisionUserNotAvailable() (from
      copilot.generated.rpc)
    
    Test changes:
    - Updated imports and client-construction assertions (kwargs-based)
    - Permission handler tests use concrete decision types
      (PermissionDecisionApproveOnce, PermissionDecisionDeniedInteractivelyByUser)
    
    Sample changes:
    - Permission handlers use PermissionHandler.approve_all or sync
      approve_and_log pattern (v1.0.0 protocol v3 dispatch is incompatible
      with blocking input() in permission handlers)
    - Function approval sample uses asyncio.to_thread for interactive prompts
    - Simplified imports across all samples
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review: scope permission handlers, widen type, add test
    
    - Shell sample: only approve kind='shell', deny others
    - URL sample: only approve kind='url', deny others
    - Use getattr() for kind-specific attributes to satisfy pyright
    - Widen PermissionHandlerType to accept async handlers (matches SDK)
    - Add test for _deny_all_permissions return value
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix validation script and strengthen test assertion
    
    - Update scripts/sample_validation/create_dynamic_workflow_executor.py to
      use copilot.session_events imports and PermissionHandler.approve_all
    - Assert isinstance(result, PermissionDecisionUserNotAvailable) instead of
      stringly-typed kind check
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add integration tests for GitHubCopilotAgent
    
    Add 6 integration tests mirroring .NET coverage:
    - Basic non-streaming response
    - Streaming response
    - Function tool invocation
    - Session context (multi-turn)
    - Session resume by ID
    - Shell command execution
    
    Tests require COPILOT_GITHUB_TOKEN env var (skipped otherwise).
    Each test cleans up its Copilot session via delete_session.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix compaction message-id collisions and tool-loop summary persistence (#6299)
    * Fix compaction message-id collisions and tool-loop summary persistence
    
    Fixes two bugs in the compaction strategies:
    
    - #5237: incremental group annotation assigned message ids by position
      within the re-annotated slice, so moving the re-annotation start back to
      a previous group start restarted ids at 0 and produced collisions
      (e.g. a user message reusing an assistant message's id), merging groups
      and causing tool-result compaction to wrongly exclude messages.
      group_messages/_ensure_message_ids now take an id_offset and guard
      against existing-id collisions; annotate_message_groups threads the
      slice start index through as the offset.
    
    - #4991: the function-invocation loop copied the message list each
      iteration, so summaries inserted by compaction landed in a throwaway
      copy and were lost across tool-loop iterations (only the persistent
      excluded flags survived). _prepare_messages_for_model_call now compacts
      the list in place when messages is a list, so inserted summaries persist.
    
    Adds regression tests (incremental id uniqueness, existing-id collision
    avoidance, idempotency, and tool-loop summary persistence including
    streaming and conversation-id modes).
    
    Also adds a summarization.py sample demonstrating SummarizationStrategy
    directly with a real client, and reworks advanced.py with tool-call
    groups and a real summarizer.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Guard incremental message-id assignment against prefix-id collisions
    
    Addresses PR review on #5237: _ensure_message_ids only guarded against
    collisions within the re-annotated slice. A preexisting (e.g. user-supplied)
    id in the preserved prefix could still be reassigned in the suffix when the
    id was numerically out of position, merging groups across the re-annotation
    boundary again.
    
    group_messages/_ensure_message_ids now accept reserved_ids, and
    annotate_message_groups passes the preserved prefix's ids so auto-assigned
    suffix ids never collide across the full list. Adds a regression test
    reproducing the out-of-position prefix-id collision.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add MCP-based skills discovery (McpSkillsSource) (#6169)
    * Add MCP-based skills discovery (McpSkill, McpSkillsSource, McpSkillResource)
    
    Implement Agent Skills discovery over MCP following the SEP-2640 convention:
    - McpSkillsSource: reads skill://index.json to discover skills served by an MCP server
    - McpSkill: lazily fetches SKILL.md content via resources/read on demand
    - McpSkillResource: wraps MCP resource results (text and binary)
    - Path traversal protection in get_resource for defense in depth
    - Samples for Foundry Toolbox and standalone MCP skills server
    - Comprehensive unit tests (514 lines)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review comments: rename to MCP* convention, fix error handling and samples
    
    - Rename McpSkill/McpSkillResource/McpSkillsSource to MCPSkill/MCPSkillResource/MCPSkillsSource
    - Add data-URI prefix stripping for blob resource decoding
    - Let non-McpError exceptions propagate from get_resource()
    - Fix contradictory test comment
    - Use interactive input() in mcp_based_skill sample
    - Remove misleading sample output block
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Restore debug logging for McpError in get_resource()
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Use AzureCliCredential in Foundry toolbox skills sample for consistency
    
    Replace DefaultAzureCredential with AzureCliCredential to match the
    credential convention used in all other samples.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Use MCPStreamableHTTPTool in MCP skills sample
    
    Replace raw mcp library imports (ClientSession, streamable_http_client)
    with the framework's MCPStreamableHTTPTool to keep MCP server connections
    consistent regardless of whether skills are enabled.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Branch on McpError.error.code so only not-found errors return empty
    
    Previously _try_read_index() and get_resource() swallowed every McpError
    as 'no skills available', making auth failures, server crashes, and
    connection drops indistinguishable from a server that simply has no
    skills.
    
    Now only two codes are treated as not-found:
    - -32002 (MCP-spec Resource not found)
    - -32601 (METHOD_NOT_FOUND — server lacks resources/read)
    
    All other McpError codes and non-McpError exceptions propagate with a
    warning log, surfacing real failures visibly.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add tests for non-McpError and non-not-found error propagation in MCP skills
    
    Cover the re-raise branch in MCPSkill.get_resource for plain
    ConnectionError/TimeoutError, the generic McpError (code 0) propagation
    on get_resource, and TimeoutError propagation in _try_read_index.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Revert "Use MCPStreamableHTTPTool in MCP skills sample"
    
    This reverts commit f31ed0ded9.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Introduce MCP_SKILLS experimental feature for MCP skill classes
    
    Add a separate MCP_SKILLS feature ID to ExperimentalFeature enum and
    use it for MCPSkillResource, MCPSkill, and MCPSkillsSource, since their
    promotion timeline is partly outside of our control.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: progressive tool exposure via FunctionInvocationContext (#6233)
    * Python: progressive tool exposure via FunctionInvocationContext
    
    Add first-class progressive tool exposure to the Python core function-calling
    loop. Tools can now add or remove real FunctionTool schemas at runtime via the
    injected FunctionInvocationContext, taking effect on the next iteration of the
    loop.
    
    - FunctionInvocationContext gains a live `tools` list plus experimental
      `add_tools()` / `remove_tools()` helpers (feature: PROGRESSIVE_TOOLS).
    - The function-calling loop establishes a run-local, normalized tools list and
      threads it into the context at both invocation paths so mutations propagate.
    - Add a sample (dynamic_tool_exposure.py) and a tools samples README, including
      a note that CodeAct providers (Monty/Hyperlight) use their own provider-level
      tool management instead.
    
    Supersedes #3877.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Validate non-negative input in dynamic_tool_exposure sample tools
    
    Address review feedback: factorial and fibonacci now return an error
    message for negative n instead of producing incorrect results.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Make add_tools atomic and surface swallowed function errors
    
    Address review feedback on progressive tool exposure:
    
    - add_tools now validates the full batch against a throwaway copy before
      committing, so a duplicate-name clash partway through a sequence leaves
      the live tool list unchanged (all-or-nothing).
    - _auto_invoke_function now logs a warning (with traceback) when a tool
      raises, so contract errors such as a duplicate-name ValueError from
      add_tools are debuggable without enabling include_detailed_errors.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Avoid retaining tracebacks when logging swallowed function errors
    
    Logging with exc_info=exc fed the exception traceback to the logging
    machinery, whose frame references created reference cycles collected
    lazily by the cyclic GC. On Windows that could drop a hyperlight
    WasmSandbox on a non-owning thread ("unsendable, dropped on another
    thread"), crashing the xdist worker. Log a pre-formatted message with
    the exception repr instead, so no traceback object is retained.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * added missing decorator
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: refresh dev dependencies and validate runtime bounds (#6238)
    Updates third-party dev dependencies across the Python workspace and
    validates that all runtime dependency bounds still hold at both ends.
    
    Dev dependency bumps (root, lab, declarative, durabletask):
    - uv 0.11.6 -> 0.11.17, ruff 0.15.8 -> 0.15.15,
      pytest-asyncio 1.3.0 -> 1.4.0, mcp 1.27.0 -> 1.27.2,
      azure-monitor-opentelemetry 1.8.7 -> 1.8.8,
      poethepoet 0.42.1 -> 0.46.0, prek 0.3.9 -> 0.4.3,
      types-python-dateutil and types-PyYaml stub bumps.
    - Transitive Dependabot items swept via lock: idna 3.11 -> 3.17,
      pip 26.0.1 -> 26.1.2.
    
    Deliberately excluded:
    - opentelemetry-sdk stays 1.40.0: azure-monitor-opentelemetry (incl.
      1.8.8) hard-pins opentelemetry-sdk==1.40.
    - mypy stays 1.20.0 and pyright stays 1.1.408: the 2.1.0 / 1.1.409
      bumps introduce new diagnostics that fail type checking and need
      dedicated PRs.
    - rich kept as a range: agentlightning (lab[lightning]) forces
      rich==13.9.4.
    
    Code/formatting changes driven by the ruff upgrade:
    - devui lifespan now uses try/finally so shutdown cleanup always runs
      (ruff RUF075).
    - Removed unused TYPE_CHECKING imports in core and foundry flagged by
      ruff 0.15.15.
    - Reapplied ruff 0.15.15 formatting to the files it changed.
    
    Validation: validate-dependency-bounds-test "*" passes (31/31 lower +
    31/31 upper); typing 62/62; lint 31/31; devui tests pass.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Reorganize A2A samples and use package A2AExecutor (#6165)
    * Reorganize A2A samples: client demos in 02-agents, use package A2AExecutor
    
    - Move client samples (agent_with_a2a, a2a_agent_as_function_tools) to samples/02-agents/a2a/
    - Add new concept samples: polling, stream reconnection, protocol selection
    - Replace sample agent_executor.py with package-level A2AExecutor (stream=True)
    - Update 04-hosting/a2a to focus on server-side, point to 02-agents for clients
    - Add README.md for the new 02-agents/a2a/ sample collection
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix streaming artifact coalescing and address PR review feedback
    
    A2AExecutor fix:
    - Generate a stable artifact_id per stream in _run_stream so all streaming
      chunks share the same ID, enabling proper append=True coalescing per the
      A2A spec (TaskArtifactUpdateEvent with same artifactId).
    - Previously, item.message_id was None for OpenAI/Foundry streaming updates,
      causing the SDK to generate a new random UUID per token (100+ separate
      artifacts instead of 1 appended artifact).
    
    Sample improvements:
    - Replace join workaround with response.text now that coalescing works
    - Add background=True to stream reconnection resume call (required for
      continuation token emission on in-progress tasks)
    - Fix type ignore specificity in polling sample
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Adding AgentFileStore and FileAccessProvider to support file access operations. (#6099)
    * Adding AgentFileStore and FileAccessProvider to support file ased operations for agents.
    
    * Address PR review feedback on FileAccessProvider
    
    - Probe symlinks on the unresolved candidate path so in-root symlinks
      cannot silently pass and out-of-root symlinks surface the correct
      error message.
    - Validate matching_lines elements in FileSearchResult.from_dict and
      raise a clean ValueError for non-mapping entries.
    - Cap search regex pattern length (256 chars) via a new
      _compile_search_regex helper to mitigate ReDoS, and surface the cap
      in the file_access_search_files tool description.
    - Skip non-UTF-8 files during filesystem search instead of aborting
      the entire directory walk.
    - Replace the module-scope trailing string in the data-processing
      sample with comments to avoid Ruff B018.
    - Remove the checked-in working/region_totals.md sample artifact so
      the save flow works from a clean checkout.
    - Expand the Windows stdout reconfiguration comment in task_runner.py
      for clarity.
    - Add tests for invalid/oversize regex, non-UTF-8 file search, and
      in-root symlink rejection.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix mypy redundant-cast in FileSearchResult.from_dict
    
    Use cast(list[object], ...) instead of cast(list[Any], ...) so the
    cast represents a real type change (lists are invariant) and is no
    longer flagged by mypy as redundant, while still satisfying pyright's
    reportUnknownVariableType. Matches the existing pattern in _memory.py.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Tighten path normalization and directory resolution in FileAccess
    
    - _normalize_relative_path now strips surrounding whitespace up front
      so leading/trailing spaces never leak into file segments, and
      rejects trailing path separators for file paths so 'foo/' is no
      longer silently coerced to 'foo'.
    - FileSystemAgentFileStore._resolve_safe_directory_path normalizes
      with is_directory=True and maps an empty normalized result to the
      root. This matches InMemoryAgentFileStore so whitespace-only
      directory inputs resolve to the root instead of raising.
    - Added tests for whitespace stripping, trailing-separator rejection,
      and whitespace-only directory listing on the filesystem store.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Harden FileAccess search and atomic save in store API
    
    - Add wall-clock timeout (10s) around regex scans so a pathological pattern (e.g. `(a+)+`) below the length cap cannot stall the event loop.
    - Offload the InMemoryAgentFileStore regex scan to a worker thread, matching the filesystem store.
    - Fail closed when `Path.is_symlink` raises during the safe-path probe so a permission error cannot silently bypass the symlink/reparse-point rejection.
    - Add `overwrite: bool = True` to `AgentFileStore.write_file`; the in-memory store performs the check under the existing lock and the filesystem store uses `open(mode='x')` so concurrent callers cannot race past `overwrite=False`.
    - `file_access_save_file` now relies on the atomic store call instead of a separate `file_exists` round-trip.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix Python 3.10 timeout handling and add directory arg to list/search tools
    
    - Catch asyncio.TimeoutError in _run_search_with_timeout. In Python 3.10
      asyncio.wait_for raises asyncio.exceptions.TimeoutError, which is
      distinct from the builtin TimeoutError (the two were unified in 3.11).
      Catching the asyncio alias works on every supported version.
    - Add an optional directory parameter to file_access_list_files and
      file_access_search_files so agents can enumerate / scope searches to
      nested folders, not just the store root.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address FileAccess review feedback: case, errors, signal, TOCTOU
    
    - InMemoryAgentFileStore now stores (display_name, content) so list_files
      and search_files return the original-case names callers wrote, matching
      the behaviour of FileSystemAgentFileStore on case-preserving filesystems
      and removing the silent in-memory vs. on-disk contract divergence.
    - FileSystemAgentFileStore.read_file raises ValueError instead of letting
      UnicodeDecodeError bubble for binary / non-UTF-8 input, restoring
      symmetry with search_files (which still skips) and giving the tool
      layer a recoverable type to translate.
    - Tool wrappers now catch ValueError and OSError around every operation
      and surface them as readable strings, so 'you used ..' and 'the file
      already exists' are both reported to the model the same way instead of
      the former crashing out as an unhandled exception.
    - _search_files_sync logs per skipped non-UTF-8 file at WARNING and an
      aggregate INFO summary so operators can distinguish 'no matches' from
      'half the corpus was unreadable'.
    - FileSystemAgentFileStore softens its docstrings to acknowledge the
      inherent probe-then-open TOCTOU window. On POSIX both read and write
      now pass O_NOFOLLOW so the kernel refuses if the leaf segment becomes
      a symlink between the probe and the open. Windows has no equivalent
      flag; the limitation is documented.
    - Tests cover: case preservation on list/search, ValueError on non-UTF-8
      read at the store and tool layer, tool-layer string responses for
      path-traversal and oversized-regex inputs, search-skip log output,
      symlink rejection on delete/search/list, and symlinked intermediate
      directory rejection.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address FileAccess nit comments: docstrings, enumerate, opt-in delete approval
    
    - Expand FileSearchMatch/FileSearchResult.to_dict docstrings to explain why
      the override is needed (__slots__ defeats the mixin's __dict__ iteration)
      and why exclude/exclude_none are accepted-but-ignored (mixin signature
      compatibility for callers like to_json).
    - Use enumerate(lines, start=1) in _search_file_content so the +1 below is
      no longer needed; rename loop variable to line_number for clarity.
    - Add opt-in require_delete_approval: bool = False on FileAccessProvider.
      When True, file_access_delete_file is registered with approval_mode
      'always_require' so the host must approve every delete. Default False
      preserves current behaviour and matches the .NET reference, but
      deployments that want a safer-by-default posture can enable it.
    - Add tests covering both delete approval modes.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * FileAccess: require delete approval by default
    
    Flip the default for FileAccessProvider(require_delete_approval=...) from
    False to True so destructive deletes are gated by host approval out of the
    box. Callers that want the previous autonomous behaviour (which matches the
    .NET reference) can pass require_delete_approval=False.
    
    Tests updated accordingly.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fixing linkinspector by installing Chrome for puppeteer first.
    
    ---------
    
    Co-authored-by: Ben Thomas <25218250+alliscode@users.noreply.github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add a HarnessAgent with available features and sample (#6041)
    * Add a HarnessAgent with available features and sample
    
    * Fix formatting
    
    * Address PR comments and fix mypy error
    
    * Add web search support to HarnessAgent
    
    * Fix build warning
    
    * Apply suggestions from code review
    
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
    
    * Address PR comments
    
    * Address PR comments
    
    * Address further PR comments.
    
    * Fix markdown broken link
    
    ---------
    
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
  • Python: feat(foundry): add to_prompt_agent / deploy_as_prompt_agent (experimental) (#5959)
    * feat(foundry): add experimental to_prompt_agent converter
    
    Adds `to_prompt_agent(agent)`, an experimental converter
    (`ExperimentalFeature.TO_PROMPT_AGENT`) that turns an Agent Framework
    `Agent` into a Foundry `PromptAgentDefinition` ready to publish via
    `AIProjectClient.agents.create_version(...)`.
    
    Behaviour:
    
    * `agent.client` must be a `FoundryChatClient` (or subclass); otherwise
      `TypeError` is raised. The model deployment name is lifted from the
      bound client so the same Agent definition used for local runs can be
      published as a hosted prompt agent without restating the model.
    * Foundry SDK tool instances (from `FoundryChatClient.get_*_tool()`) are
      passed through unchanged. AF `FunctionTool`s (and `@tool`-decorated
      callables) are emitted as Foundry `FunctionTool` declarations.
    * Local AF MCP tools cannot be expressed in a `PromptAgentDefinition`;
      the converter raises `ValueError` and points at
      `FoundryChatClient.get_mcp_tool()` for hosted MCP servers.
    * The converter walks both `agent.default_options["tools"]` and
      `agent.mcp_tools` because `normalize_tools()` splits local MCP off
      into its own list.
    
    Re-exported through the `agent_framework.foundry` lazy-loading namespace
    (updates both `__init__.py` and the `__init__.pyi` type stub).
    
    Adds a portable-agent sample showing the same `Agent` driven through
    both `agent.run(...)` and `to_prompt_agent(agent)`, and a README section
    covering the new converter.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * chore(samples): remove snippet tags from portable agent sample
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * chore(samples): inline FoundryChatClient and enable prompt-agent publish
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * chore(samples): drop async credential context manager
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(foundry): trim README to_prompt_agent example to publish-only flow
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(foundry): note FoundryAgent runs @tool callables for deployed prompt agents
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(foundry): address review comments on to_prompt_agent converter
    
    * Construct `PromptAgentDefinition` `Tool` from a dict via `**tool_item`
      unpacking rather than the positional Mapping constructor \u2014 cleaner and
      matches the typical Pydantic / Azure SDK pattern.
    * Drop the redundant `isinstance(mcp_tool, MCPTool)` guard in
      `_convert_tools`; the parameter is already typed `Iterable[MCPTool]` so
      the second `raise` was unreachable. The remaining single `raise`
      fires for every entry as intended.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(foundry): match Agent.__init__ model resolution in to_prompt_agent
    
    * Read the model from `agent.default_options.get("model")` first,
      falling back to `agent.client.model`. This mirrors the order
      `Agent.__init__` uses (`_agents.py:740`) when assembling
      default_options, so the model the agent runs with is the same model
      the converter publishes \u2014 e.g. when the caller passes
      `default_options={"model": "..."}` to override the bound client.
    * Updated the missing-model error message to point at both the client
      and the default_options paths.
    * Added tests:
      * tool-only agent with no `instructions` produces a definition
        where `instructions` is `None` and is omitted from the dict
        payload (`Agent.__init__` strips None values from default_options
        before storing them).
      * `default_options['model']` wins over the bound client's model.
      * Fallback to client.model when default_options has no model.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * feat(foundry): add deploy_as_prompt_agent helper + samples
    
    Adds `deploy_as_prompt_agent(agent)`, a convenience wrapper around
    `to_prompt_agent` that reuses the bound FoundryChatClient's project
    client to call `project_client.agents.create_version(...)`. Defaults
    `agent_name` / `description` from `agent.name` / `agent.description`
    so the Agent stays the single source of truth.
    
    * Exposed from `agent_framework_foundry` and the lazy-loading
      `agent_framework.foundry` namespace (including the .pyi stub).
    * Marked experimental with the existing
      `ExperimentalFeature.TO_PROMPT_AGENT` tag.
    * Tests cover the happy path, name/description defaulting, explicit
      override, no-name error, metadata + description forwarding, extra
      kwargs passthrough, and the experimental metadata.
    
    Samples:
    * Renamed the existing sample to `creating_prompt_agents.py`, drops
      'portable' wording, presents `deploy_as_prompt_agent` first as the
      recommended path and `to_prompt_agent` + `AIProjectClient` as the
      two-step alternative, and adds a cleanup step that deletes the
      published agent so re-runs stay idempotent.
    * New `using_prompt_agents.py` shows the end-to-end loop: deploy the
      agent, connect to it with `FoundryAgent` passing the same local
      `@tool` callable, run a query against the deployed prompt agent,
      then clean up.
    
    README updated to introduce `deploy_as_prompt_agent` as the
    recommended path and link to both runnable samples.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(foundry): restore missing-model ValueError in to_prompt_agent
    
    The check was accidentally dropped while reworking docstrings in the
    previous commit. Test `test_to_prompt_agent_rejects_missing_model`
    exercises this path and was failing on CI as a result.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(foundry): rename deploy_as_prompt_agent -> create_prompt_agent
    
    Renames the helper across the foundry package, core lazy-loader stubs,
    tests, README and samples. The new name better matches the action
    performed (a prompt-agent definition is created in Foundry) and is
    consistent with the surrounding ''create_*'' API surface.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(foundry): drop create_prompt_agent, enrich to_prompt_agent params
    
    Remove the create_prompt_agent helper and consolidate on to_prompt_agent.
    Expose every PromptAgentDefinition parameter that has either an Agent
    Framework equivalent (sourced from default_options) or no equivalent
    (accepted as a keyword argument).
    
    * default_options-sourced (with kwarg overrides):
      temperature, top_p, string tool_choice
    * kwarg-only Foundry knobs:
      reasoning, text, structured_inputs, rai_config, ToolChoiceParam tool_choice
    
    Precedence is always: explicit keyword > default_options entry > unset.
    
    Tests cover every path (defaults, default_options, kwargs, kwarg override).
    Samples and README rewritten around the enriched to_prompt_agent.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(foundry): single source of truth for prompt-agent options
    
    Stop duplicating the generation-parameter surface between FoundryChatOptions
    and to_prompt_agent. Translate every field with an Agent Framework equivalent
    (temperature, top_p, tool_choice, reasoning, response_format/text/verbosity)
    from agent.default_options via a new RawFoundryChatClient helper
    _prepare_prompt_agent_options. Only Foundry-specific fields with no AF
    equivalent — structured_inputs and rai_config — remain as keyword arguments
    on to_prompt_agent.
    
    - tool_choice is dropped when there are no tools (mirrors _prepare_options
      semantics and avoids polluting tool-less prompt agents with Agent.__init__'s
      'auto' default).
    - response_format Pydantic models route through
      openai.lib._parsing._responses.type_to_text_format_param; dict shapes go
      through the existing _prepare_response_and_text_format helper.
    - default_options is not mutated; text dict is defensively copied.
    
    Tests, README, and creating_prompt_agents.py sample updated to reflect the
    new single-source model.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(foundry): consolidate prompt-agent sample
    
    Drop creating_prompt_agents.py (the publish-only variant) and rename
    using_prompt_agents.py to foundry_prompt_agents.py so the single sample
    covers the full convert -> publish -> connect -> run loop. Update the
    README link list accordingly.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(foundry): run local Agent + deployed agent in same sample
    
    Add an agent.run() call against the local Agent before publishing, then run
    the deployed prompt agent on the same query. Expand the docstring with a
    compare-and-contrast covering runtime/latency, configurability, and
    persistence/sharing differences between the two execution paths.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * test(foundry): cover conflicting response_format + text.format in to_prompt_agent
    
    Exercises the ValueError path when a Pydantic response_format would overwrite
    an explicit text.format mapping with a different shape. Lifts _chat_client.py
    coverage from 89% to 90%.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(foundry): move _prepare_prompt_agent_options into _to_prompt_agent
    
    Lift the translation helper off RawFoundryChatClient and into the
    _to_prompt_agent module as a module-private function that takes the client
    as its first argument. The chat client no longer needs to carry a method
    whose only consumer is the prompt-agent converter, while still serving as
    the source of the request-path helper (_prepare_response_and_text_format)
    that the converter reuses for dict-shaped response_format values.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(python): codify GA terminology + post-run docs review
    
    Add two pieces of guidance to python/AGENTS.md:
    
    * Terminology - reserve 'GA' for hosted services; use 'released' or 'stable'
      for Agent Framework code/features to match the feature-lifecycle stages.
    * Maintaining Documentation - review AGENTS.md and skills at the end of every
      run and update any guidance the conversation made stale; before adding a
      new principle, ask the user to confirm it should be captured.
    
    Also pulls in a docstring fix in foundry_prompt_agents.py that swaps the
    stray 'GA' for 'released', applying the new terminology rule.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * address PR review: strict=True default, Tool._deserialize dispatch, sample cleanup safety
    
    - FunctionTool published as strict=True so the server-side schema validation
      matches what the local FoundryAgent(tools=[same_callable]) dispatcher
      enforces. AF FunctionTool has no 'strict' attribute, so the safer default
      is used uniformly instead of silently downgrading to a permissive contract.
    - _validate_mapping_tool now dispatches through ProjectsTool._deserialize so
      dict-shaped tools rehydrate to the concrete subclass (FunctionTool,
      WebSearchTool, ...) via the 'type' discriminator instead of returning a
      generic Tool. Added a test that asserts isinstance(WebSearchTool) and a
      new test for the function-typed dict path.
    - foundry_prompt_agents.py sample now wraps credential + project client in
      async with and the create_version / run flow in try/finally so a failure
      on connect or run still deletes the published prompt agent rather than
      leaving an orphaned, billable resource in the user's Foundry project.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(ci): correct linkspector ignorePattern typo (./pulls -> ./pull)
    
    GitHub PR URLs use the singular segment /pull/N (compare to /issues/N
    for issues). The existing './pulls' ignore pattern never matched
    anything as a result, so legitimately stale PR links (e.g. PRs deleted
    from forks) surface as linkspector failures on unrelated PRs.
    
    This is the same convention the './issues' rule above already follows.
    Fixes the markdown-link-check failure on a dangling link in
    dotnet/src/Microsoft.Agents.AI.DurableTask/CHANGELOG.md.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Shell tool with support for local and Docker (#5664)
    * feat(tools): add cross-OS LocalShellTool in new agent-framework-tools package
    
    Introduces a safe, cross-OS local shell tool as the first citizen of a new
    
    agent-framework-tools workspace package. Supports persistent (default) and
    
    stateless modes across pwsh/powershell.exe/bash/sh, with policy denylist,
    
    allowlist, approval gating, process-tree kill on timeout, output truncation,
    
    and audit hooks. Integrates with existing provider get_shell_tool(func=...)
    
    factories via FunctionTool kind='shell'.
    
    See docs/decisions/0026-builtin-tools-local-shell.md for the full design.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * feat(tools): security hardening for LocalShellTool
    
    Codifies what LocalShellTool does and does not defend against, and
    
    delegates the security-relevant lifecycle primitive to a battle-tested
    
    library instead of hand-rolled per-OS code.
    
    Changes:
    
    - Adopt psutil for cross-OS process-tree termination (executor + session).
    
      Replaces hand-rolled taskkill/killpg with one canonical implementation.
    
    - Resolve taskkill.exe to absolute %SystemRoot%\System32 path so PATH
    
      poisoning cannot redirect us to an attacker-supplied binary.
    
    - Reframe ShellPolicy docstring + ADR + README: denylist is a guardrail,
    
      not a security boundary.
    
    - Require acknowledge_unsafe=True to set approval_mode='never_require',
    
      making the unsafe path explicitly opt-in with a self-documenting name.
    
    - Add tests/test_security.py codifying named CVE-style cases. Defenses
    
      we DO claim are asserted; non-defenses (denylist bypasses via
    
      backslash insertion, variable expansion, interpreter escape, base64,
    
      alternative tools, PowerShell-native verbs) are documented as
    
      expected-to-pass tests so residual risk stays visible.
    
    - Add Threat Model + Confidence Strategy sections to ADR 0026.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * feat(tools): add DockerShellTool sandboxed shell tier
    
    Adds a container-backed shell executor as the recommended pattern for untrusted-input shell workflows. The container provides the security boundary (--network none, non-root user, --read-only, --cap-drop ALL, no-new-privileges, memory/pids limits, tmpfs /tmp), so approval gating is optional unlike LocalShellTool.
    
    Also introduces a ShellExecutor Protocol so callers can plug in custom backends (Firecracker, SSH, WASI) without forking the framework.
    
    Removes the planned HyperlightShellExecutor follow-up from ADR 0026: Hyperlight is a WASM code sandbox with no kernel/userland/shell binary, so a Hyperlight-backed shell is not viable. Docker is the realistic sandbox tier for shell.
    
    Tests: 11 unit tests for argv builders + lifecycle (no Docker daemon required); 3 integration tests gated on is_docker_available().
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(tools): backport shell-tool fixes from .NET parity review
    
    Applies the applicable subset of bug fixes accumulated during the
    .NET shell-tool PR review (microsoft/agent-framework#5604) to the
    Python shell tool.
    
    A1 - Quote workdir safely in _maybe_reanchor
    
      Previously _tool.py used double-quote interpolation when emitting
      the cd/Set-Location prefix, which expanded $VAR, $(), and backticks
      in the workdir path. A workdir containing shell metacharacters could
      trigger arbitrary command execution before the user command ran.
    
      Replaced with single-quote escaping helpers _quote_posix and
      _quote_powershell that emit literal-string forms safe for both
      hosts.
    
    A5/A6 - Consolidate truncation to a single byte-aware helper
    
      Extracted a shared truncate_head_tail / truncate_text_head_tail
      helper in _truncate.py. The new implementation distributes odd
      caps so head receives floor(cap/2) and tail receives ceil(cap/2)
      bytes, matching the .NET round-9 fix and ensuring no input bytes
      are silently dropped on the boundary.
    
      _session.py previously truncated by Python str length while the
      caller passed _max_output_bytes - the unit mismatch is now gone:
      raw byte buffers go through truncate_head_tail and decoded text
      goes through truncate_text_head_tail.
    
    Unit tests added for the truncate and quote helpers.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(tools): tone down narrative and overconfident comments in shell tool
    
    The shell tool's docstrings and comments contained two patterns that
    the .NET review pushed back on:
    
    - Narrative framing about implementation history ("hard-won",
      "we sidestep", "design inspiration: ...", competitor framework
      name-drops in module docstrings).
    - Overstated security guarantees ("battle-tested",
      "reasonable for untrusted input", "recommended executor for any
      agent that runs commands from untrusted input",
      "destructive commands are blocked", "safe local shell tool",
      "blocks shell injection").
    
    Rewrites the affected docstrings and comments to describe what the
    code does in neutral terms. Behaviour is unchanged.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * feat(tools): add ShellEnvironmentProvider for the Python shell tool
    
    Ports the .NET ShellEnvironmentProvider as a Python ContextProvider
    so agents using LocalShellTool or DockerShellTool can be primed with
    an accurate description of the shell they're talking to (family,
    version, OS, working directory, and which CLIs are available).
    
    The provider runs probes through any ShellExecutor, caches the
    resulting snapshot, and on every before_run extends the session
    instructions with a markdown block describing the shell idiom to
    use. A failed first probe leaves the cache empty so the next call
    retries (no permanent poisoning).
    
    Probe failures from a narrow set of expected error types
    (ShellCommandError, ShellExecutionError, ShellTimeoutError, and
    asyncio.TimeoutError from the per-probe timeout) are recorded as
    None fields in the snapshot. Other exceptions propagate. Tool
    names are validated against ^[A-Za-z0-9._-]+$ before being
    interpolated into a probe command.
    
    Includes 12 unit tests covering happy path, stderr fallback,
    timeout handling, expected/unexpected exception paths, malicious
    tool name rejection, case-insensitive deduplication, retry after
    failure, concurrent first-callers sharing one probe, and the
    default and custom formatter paths.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(tools): document ShellEnvironmentProvider and finish comment cleanup
    
    Add a README section introducing ShellEnvironmentProvider, soften two remaining overconfident security-boundary comments in _executor_base.py and the DockerShellTool class docstring, and add a sample (shell_with_environment_provider.py) that demonstrates the provider in stateless and persistent modes.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(tools): move shell samples to python/samples/02-agents/tools
    
    The repository convention is to host samples under python/samples/ rather than inside the package directory. Move the two net-new shell samples (allow-list and environment-provider) to python/samples/02-agents/tools/ and drop the in-package samples/ directory; the existing top-level providers/openai/client_with_local_shell.py already covers the basic LocalShellTool walkthrough.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * test(tools): cover confine_workdir default and ShellResult.format_for_model
    
    Two new tests in test_local_shell_tool.py exercise the default confine_workdir=True behaviour on POSIX and PowerShell, asserting that 'cd' inside one persistent-mode call does not leak into the next. A new test_shell_result.py module provides direct unit coverage for every conditional branch of ShellResult.format_for_model (stdout, truncated, stderr, timed_out, exit_code) so regressions in the LLM-facing format are caught immediately.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(tools): address PR #5664 review feedback
    
    - _tool.py: detect PowerShell via is_powershell() helper instead of basename string match
    
    - _environment.py: use public ContextProvider import (no private _ prefix)
    
    - _session.py: trim _stdout_buf/_stderr_buf after copying to avoid unbounded retention across calls
    
    - _docker.py: short-circuit start()/close() in stateless mode; add configurable shell kwarg (default bash, e.g. 'sh' for alpine)
    
    - tests: parenthesized multi-line assert; alpine integration tests now pass shell='sh'
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(tools): satisfy CI quality gates
    
    - pyupgrade: drop quoted self-class refs in __aenter__/method annotations
    
    - ruff format: reflow long lines per workspace style
    
    - pyright: assert psutil non-None in optional-import branch; lowercase mutable module globals; annotate _approval_mode as Literal so tool() Literal-typed kwarg is accepted; add ... body to ShellExecutor.run protocol; remove unused deprecated _kill_tree wrapper
    
    - tests: skip docker integration tests on win32 (Windows containers don't support --read-only / alpine images)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove DEFAULT_DENYLIST; document single-session ownership; fix bandit findings
    
    Mirrors the .NET PR #5604 cleanup:
    
    - Remove DEFAULT_DENYLIST from ShellPolicy. ShellPolicy() now ships with an empty deny-list; operators opt into site-specific patterns explicitly. No major agent framework uses regex matching as a primary security control; AutoGen v2 removed theirs. Approval gating + sandbox tier remain the real boundaries.
    
    - Rewrite module / class docstrings to frame ShellPolicy as a UX pre-filter, not a security control.
    
    - Add Single-session ownership paragraphs to ShellExecutor, ShellSession, LocalShellTool, and DockerShellTool: a persistent-mode tool is owned by exactly one conversation / agent session; do not share across users or concurrent conversations.
    
    - Tests now supply explicit deny patterns instead of relying on a default.
    
    - Address Pre-commit Hooks (bandit) CI failures: convert internal-invariant asserts to explicit RuntimeError, annotate intentional subprocess/shell usage with # nosec, document container-internal /tmp paths.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR #5664 round-2 review feedback
    
    Deny-list documentation drift:
    
    - README and the OpenAI/local-shell sample no longer claim a built-in deny-list of destructive commands. ShellPolicy is described as an optional, operator-supplied UX pre-filter; the real boundaries remain approval gating and the sandbox tier.
    
    Behavioural fixes called out in review:
    
    - ShellPolicy.evaluate() now denies empty / whitespace-only commands explicitly instead of returning allow with no rationale.
    
    - truncate_head_tail() raises ValueError for cap <= 0 instead of silently returning the full input with truncated=False, which previously could defeat output-capping in callers that mis-configured the budget.
    
    - LocalShellTool.as_function() / DockerShellTool.as_function() return the ShellCommandError text directly so the model sees a single, non-redundant 'Command rejected by policy: …' message instead of the prior duplicated 'Command blocked by policy: Command rejected …' wrapping.
    
    - ShellSession POSIX sentinel trailer now snapshots and restores the prior errexit (set -e) state around the trailer, so a user 'set -e' in the persistent shell is no longer permanently disabled by the next run().
    
    Tests:
    
    - New test_shell_parse_rc.py covers the full _parse_rc() edge-case surface (zero, positive, negative, CRLF, no newline, missing prefix, empty input, non-digits, trailing garbage, partial digits).
    
    - test_policy.py asserts the new empty-command deny.
    
    - test_shell_truncate_and_quote.py asserts ValueError for cap=0 and cap<0.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback for shell tool
    
    - _resolve.py: reject empty/whitespace shell override string
    - _tool.py / _docker.py: mode-aware default tool description (persistent vs stateless)
    - _tool.py: fix misleading workdir docstring (re-anchor, not blocking)
    - _types.py: emit stream-agnostic [output truncated] marker
    - _policy.py: declare _denies/_allows as dataclass fields
    - _environment.py: use $(pwd) instead of $PWD in POSIX probe
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback: shell override flag + probe timeout safety
    
    - _resolve.py: in stateless mode, ensure shell overrides end with -c/-Command so commands aren't misinterpreted as script-file paths.
    - ShellExecutor.run / LocalShellTool.run / DockerShellTool.run now accept an optional 	imeout kwarg; ShellEnvironmentProvider drops the outer asyncio.wait_for and lets the executor enforce the probe timeout internally, so cancellation no longer risks leaving a hung subprocess or corrupted session.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback: docker isolation + lifecycle robustness
    
    - pyproject.toml: bump agent-framework-core minimum from 1.2.0 to 1.2.2 to align with the rest of the workspace.
    - _docker.py: validate extra_run_args at construction time and reject flags that would dismantle the isolation defaults (--privileged, --cap-add, --security-opt, --network/--net, -v/--volume/--mount, --device, --pid, --ipc, --userns, --user, --read-only, --tmpfs, --add-host, --gpus, --cgroupns, --device-cgroup-rule); also documented the warning on the docstring.
    - _docker._stop_container: retry docker rm -f once and log a warning/error when it does not succeed, so operators can audit leaked containers instead of getting a silent success.
    - _docker._run_stateless timeout path: fall back to docker rm -f when docker kill fails or times out (--rm only reaps on clean exit), and log instead of silently swallowing communicate() errors.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: alliscode <25218250+alliscode@users.noreply.github.com>
  • [BREAKING] Python: Enable instrumentation by default (#5865)
    * Enable instrumentation by default
    
    * Update samples
    
    * Optimization when span is not recording
    
    * Address Copilot comments
    
    * Revert uv.lock
    
    * Add warning
    
    * Formatting
    
    * Fix mypy
    
    * Add disable_instrumentation() with sticky user-intent semantics
    
    Add a public disable_instrumentation() entry point so users can explicitly opt
    out of Agent Framework telemetry, with a sticky-disable flag that makes the
    user's intent "leading" — no framework code path (foundry's
    configure_azure_monitor, configure_otel_providers, enable_instrumentation,
    enable_sensitive_telemetry, or direct OBSERVABILITY_SETTINGS.enable_*
    writes) can re-enable instrumentation until the user explicitly clears the
    disable with enable_instrumentation(force=True) /
    enable_sensitive_telemetry(force=True).
    
    Also addresses the two remaining unresolved review threads on the PR:
    1. test_observability_settings_defaults_instrumentation_true pins the new
       "ENABLE_INSTRUMENTATION defaults to True when env unset" behavior.
    2. test_enable_instrumentation_reads_env_sensitive_data restores coverage
       for the post-import load_dotenv() fallback path.
    
    Implementation:
    - ObservabilitySettings.enable_instrumentation / enable_sensitive_data become
      properties backed by _enable_*. While _user_disabled is True, the getters
      return False and the setters drop True writes (defense in depth so third-
      party writes can't subvert the disable).
    - Public is_user_disabled read-only property lets integrations (e.g. foundry's
      configure_azure_monitor) cheaply check the disable state without poking at
      privates.
    - enable_instrumentation() and enable_sensitive_telemetry() short-circuit with
      an info log when disabled; gain a force=True kwarg that clears the disable.
    - configure_otel_providers() still creates providers / exporters / views so a
      later force-enable can use them, but logs an info message when called while
      disabled.
    - Foundry's FoundryChatClient.configure_azure_monitor and
      FoundryAgent.configure_azure_monitor early-return when the user has
      disabled, so Azure Monitor's global providers aren't installed unnecessarily.
    
    Tests: 11 new tests covering default-on, env re-read at call time, sticky
    behavior against each re-enable surface (enable_instrumentation,
    enable_sensitive_telemetry, configure_otel_providers, direct attribute
    writes), force=True override, re-arming the disable, and the __all__ export.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs: document disable_instrumentation() and force=True paths
    
    Add a "Disabling instrumentation" section to the observability sample README
    that walks through:
    
    - The distinction between the ENABLE_INSTRUMENTATION env var (initial,
      non-sticky) and disable_instrumentation() (process-wide, sticky).
    - Why the sticky semantics matter: framework integrations like
      FoundryChatClient.configure_azure_monitor() can call
      enable_instrumentation() as part of their setup, and the user's opt-out
      needs to win.
    - All five surfaces guarded by the sticky disable (property reads, public
      enable functions, configure_otel_providers, direct attribute writes,
      is_user_disabled-aware integrations).
    - The force=True escape hatch on both enable_instrumentation() and
      enable_sensitive_telemetry().
    - How third-party integrations should consult OBSERVABILITY_SETTINGS.is_user_disabled.
    - The limits of the disable (does not tear down existing providers /
      in-flight spans / third-party instrumentation, does not persist across
      processes).
    
    Cross-links the new section from the ENABLE_INSTRUMENTATION row in the env
    vars table.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs: soften disable_instrumentation() overclaim about telemetry guarantees
    
    Replace 'no telemetry will be emitted no matter what' (which is too strong,
    since callers can still pass force=True or mutate private attributes) with
    language framing the disable as a user-intent contract that library and
    framework code is expected to honor: the framework actively short-circuits
    the public enable paths, force=True and private-attribute writes are
    acknowledged as out-of-contract escape hatches that integrations should
    not use on the user's behalf.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs: correct observability Dependencies section
    
    - opentelemetry-sdk is no longer a hard dependency; it is lazily imported by
      create_resource(), create_metric_views(), and configure_otel_providers()
      with a clear ImportError when missing. Day-to-day instrumentation works
      with opentelemetry-api alone provided some other component configures the
      global OpenTelemetry providers (Azure Monitor, an APM agent, application
      bootstrap, etc.).
    - opentelemetry-semantic-conventions-ai is no longer used anywhere in the
      source; remove it from the listed dependencies.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs: replace stale observability migration guide with current PR's only relevant migration
    
    The old guide documented the move away from setup_observability(otlp_endpoint=...)
    which was an earlier-release API change unrelated to this PR and stale enough that
    it's more confusing than helpful at this point. Replace it with a short note on the
    single migration this PR introduces: callers of
    enable_instrumentation(enable_sensitive_data=True) should switch to
    enable_sensitive_telemetry(). Cross-link to the Disabling instrumentation section
    for the rare 'force on without enabling sensitive data' use case where
    enable_instrumentation() still applies.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: feat: add agent-framework-monty (Monty-backed CodeAct provider) (#5915)
    * Python: feat: add agent-framework-monty (Monty-backed CodeAct)
    
    New alpha package that wraps pydantic-monty (a Rust-based Python
    interpreter) behind the same CodeAct API surface as
    agent-framework-hyperlight, so users can swap providers with minimal
    code change.
    
    Public API (agent_framework_monty):
    - MontyCodeActProvider — ContextProvider that injects a run-scoped
      execute_code tool plus dynamic CodeAct instructions.
    - MontyExecuteCodeTool — standalone FunctionTool for mixed-tool agents
      or manual static wiring.
    - FileMount / FileMountInput / MountMode — public types mirroring the
      Hyperlight names, with Monty's mode (read-only/read-write/overlay)
      and write_bytes_limit on FileMount.
    
    Constructor kwargs (both classes) mirror Hyperlight where possible:
    tools, approval_mode, workspace_root, file_mounts; plus a Monty-only
    resource_limits forwarding ResourceLimits to Monty.start().
    
    Filesystem flow:
    - workspace_root auto-mounts at /input (read-write), matching Hyperlight.
    - file_mounts accepts string shorthand, (host, mount) tuple, or
      FileMount with mode + write cap.
    - Files written under read-write mounts are scanned post-execution and
      returned as Content.from_data items (mirrors Hyperlight /output).
    - overlay mounts buffer writes in-memory; read-only mounts reject writes.
    
    Internals:
    - _monty_bridge.InlineCodeBridge ports the inline (non-durable) bridge
      from anthonychu/maf-codeact-monty-python; handles FunctionSnapshot /
      FutureSnapshot pause/resume, dispatches direct typed calls + the
      call_tool fallback, forwards mount/limits to Monty.start(...).
    - generate_type_stubs emits per-tool stubs so Monty's `ty` type-checker
      rejects bad calls before any host tool runs.
    
    Alpha-policy compliance (per python-package-management skill):
    - Added agent-framework-monty = { workspace = true } to root
      pyproject.toml.
    - Added row to python/PACKAGE_STATUS.md.
    - Added monty entry under Experimental in python/AGENTS.md.
    - NOT added to core[all]; NO agent_framework.monty lazy shim (deferred
      to beta promotion).
    
    Samples (three sets, import from agent_framework_monty directly):
    - samples/02-agents/context_providers/code_act/monty_code_act.py
      (provider pattern) + updated local README.
    - samples/02-agents/tools/monty_code_interpreter/ (standalone +
      manual-wiring + README).
    - samples/04-hosting/foundry-hosted-agents/responses/11_monty_codeact/
      (full hosted-agent layout with uv-based pyproject.toml + Dockerfile,
      Azure Monitor wiring via APPLICATIONINSIGHTS_CONNECTION_STRING +
      enable_instrumentation, ENABLE_INSTRUMENTATION and
      ENABLE_SENSITIVE_DATA env vars). The alpha wheel is vendored into
      ./wheels/ (gitignored) via vendor-wheel.sh; new row added to the
      parent Responses-API README.
    
    Tests:
    - 28 hermetic unit tests (stubbed pydantic_monty).
    - 18 integration tests marked @pytest.mark.integration, auto-skipped
      when pydantic_monty is unimportable; exercise the real Monty
      runtime: print round-trip, last-expression value, direct typed
      tool dispatch, call_tool fallback, async tool, asyncio.gather
      parallelism, ty type-check rejection, OS blocked by default,
      workspace_root read+write capture, read-only / overlay mount
      semantics, resource_limits.max_duration_secs abort, approval
      gating end-to-end, full Agent run with a scripted chat client.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: fix: monty FileMount test compares against the normalized POSIX path
    
    The shorthand string mount goes through _normalize_mount_path, which
    rewrites Windows drive letters like 'C:\\Users\\...' into
    '/C:/Users/...' (POSIX-style). The Windows CI runners surfaced this
    because tmp_path resolves to a backslashed Windows path; the test was
    comparing against the raw str(host_a) instead of the normalized form.
    
    Compare against _normalize_mount_path(str(host_a)) so the assertion is
    platform-independent.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: fix: address PR #5915 review feedback
    
    - _execute_code_tool docstring: clarify that the Monty backend supports
      scoped filesystem access via workspace_root / file_mounts (blocked by
      default).
    - _to_monty_mount: import pydantic_monty lazily through load_monty so
      missing-dependency errors surface as the same actionable RuntimeError
      the rest of the package raises (not a bare ImportError at module load).
      Renamed _load_monty -> load_monty for the same reason.
    - _python_type_repr: emit None for type(None) instead of Any, and
      normalize both typing.Union[...] and PEP-604 X | Y to PEP-604 syntax
      so Optional[X] / Union[..., None] / -> None signatures round-trip
      correctly through ty validation. Added a regression test.
    - _PrintCollector: track a running character count instead of
      recomputing sum(len(c) for c in self.chunks) per callback. Eliminates
      the O(n^2) cost on print-heavy code.
    - Instructions: mention that the value of the final expression is also
      returned alongside captured stdout (matches actual behavior).
    - 11_monty_codeact Dockerfile: pin ghcr.io/astral-sh/uv to 0.11.6
      instead of :latest for reproducible builds.
    - 11_monty_codeact README: replace the bare "see parent README" pointer
      with sample-specific steps (./vendor-wheel.sh + uv sync + uv run),
      since the sample uses pyproject.toml + a vendored wheel rather than
      requirements.txt.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: sample: 11_monty_codeact installs agent-framework-monty from PyPI
    
    Drop the vendored-wheel scaffolding now that agent-framework-monty is on
    PyPI as an alpha (1.0.0a*) release:
    
    - pyproject.toml: remove [tool.uv.sources] override; keep [tool.uv]
      prerelease = "allow" so uv pulls the alpha automatically.
    - Dockerfile: drop the COPY wheels/ step.
    - README: drop the ./vendor-wheel.sh setup step and the
      not-yet-on-PyPI warning.
    - Delete vendor-wheel.sh and the gitignored wheels/ directory.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: fix(monty): harden post-execution file capture against symlink escape
    
    Same class of issue as the MSRC-reported Hyperlight finding: the
    post-execution capture walked workspace_root with Path.rglob() +
    is_file() + read_bytes() - all of which follow symlinks. An attacker
    who controls the workspace (cloned repo, extracted archive, shared
    workspace) could pre-place `workspace/leak.txt -> /etc/passwd` or
    `workspace/outside_dir -> /etc/` and have host files surface as
    captured Content items.
    
    Monty's mount layer already rejects symlink reads from inside the
    sandbox across all three modes (verified empirically), so the runtime
    path was safe. This commit closes the post-execution scan path.
    
    Changes:
    - New `_iter_real_files(root)` walker that uses iterdir() +
      is_symlink() to skip symlinks at every directory level and yields
      only real files. Replaces the previous `host_root.rglob("*")` calls
      in both `_snapshot_writable_mounts` and `_capture_written_files`.
    - Use `Path.lstat()` instead of `Path.stat()` so size/mtime can never
      be taken from a symlink target.
    - Three new integration tests reproducing the MSRC attack shape
      against the workspace_root flow: symlink-to-file outside workspace,
      symlink-to-directory outside workspace, and a guard ensuring
      legitimate sandbox writes are still captured when symlinks are
      present.
    
    Per user request, hyperlight is untouched in this commit (separate fix).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: fix(monty): skip symlink regression tests when unsupported
    
    Apply the same Windows-CI safety guard as the hyperlight fix in PR #5919:
    the three symlink integration tests create symlinks via Path.symlink_to(),
    which fails with OSError / NotImplementedError on unprivileged Windows
    runners. Add a local _symlinks_supported helper (mirroring the one in
    packages/core/tests/core/test_skills.py) and pytest.skip when symlinks
    aren't available, so the tests no longer fail for environment reasons.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: fix(monty): address PR #5915 follow-up review feedback
    
    - _invoke_tool: drop the inspect.iscoroutinefunction(...) branch and
      always `await self.tool_map[name](**kwargs)`. Every entry in
      tool_map is `partial(FunctionTool.invoke, skip_parsing=True)` and
      FunctionTool.invoke is `async def`, so the branching was dead code -
      and on Python versions affected by cpython#98590,
      iscoroutinefunction(partial(bound_async_method, ...)) returns False,
      causing the bridge to take the asyncio.to_thread path, return an
      unawaited coroutine, and surface it as a JSON-serialization failure
      for every tool call. Added a regression test
      test_invoke_tool_awaits_partial_wrapped_async_method.
    
    - generate_type_stubs: skip tools whose name is not a valid Python
      identifier or is a Python keyword. FunctionTool.name has no upstream
      validation, so a name like "weird-name" produced a syntax error in
      the stubs and a name like "broken\n    pass\nasync def injected"
      would inject arbitrary stub source. Non-identifier names stay
      reachable via `call_tool("weird-name", ...)` at runtime; they just
      don't get type-checked stubs. Added regression test
      test_generate_type_stubs_skips_non_identifier_tool_names.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Support list[str] arguments for file-based skill scripts (#5850)
    Port of .NET PR #5475. Broadens the args type from dict[str, Any] | None
    to dict[str, Any] | list[str] | None across the skill script API surface,
    enabling CLI-style argv forwarding to subprocess scripts.
    
    Changes:
    - SkillScript.run(), InlineSkillScript.run(), FileSkillScript.run(): widen
      args type; InlineSkillScript rejects list with TypeError
    - FileSkillScript.parameters_schema: returns array-of-strings schema
    - FileSkill.content: appends <scripts> block with parameters_schema
    - SkillScriptRunner protocol: widen args type
    - SkillsProvider._run_skill_script: widen args type
    - run_skill_script tool schema: accept object, array, or null
    - subprocess_script_runner sample: accept list[str], reject dict
    - class_based_skill sample: fix missing SkillFrontmatter wrapper
    - Standardize 'folder' to 'directory' in docstrings (#5712)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • [Python] [Breaking] Extract skill spec metadata into SkillFrontmatter (#5775)
    * Fix Skill docstring consistency and spelling
    
    - Add ClassSkill to Skill class docstring concrete implementations list
    - Normalize 'defence' to 'defense' for American English consistency
    - Remove extra blank line in InlineSkill docstring example
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix E501 line-too-long lint error in test_skills.py
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix stale test section header to reflect SkillFrontmatter API
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix metadata children overriding top-level frontmatter fields
    
    Scope YAML_KV_RE to column-0 keys only so indented children
    under metadata: are not mistakenly parsed as top-level fields.
    Add regression test and spec fields to sample SKILL.md files.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Upgrade github-copilot-sdk to v1.0.0b2 with new features (#5665)
    * Upgrade github-copilot-sdk to v1.0.0b1 and implement new features
    
    - Bump github-copilot-sdk dependency from 0.2.1 to 1.0.0b1
    - Fix breaking type renames: ErrorClass -> ToolExecutionCompleteError,
      Result -> ToolExecutionCompleteResult
    - Add instruction_directories support in GitHubCopilotOptions (session-level)
    - Add copilot_home support in GitHubCopilotSettings (client-level)
    - Add sample: github_copilot_with_instruction_directories.py
    - Update README with new env var and sample entry
    - Add 8 new unit tests covering the new features (103 total, 96% coverage)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * mypy fix
    
    * small fix
    
    * Address PR feedback: fix resume path, remove copilot_home from Options, bump to beta.2
    
    - Forward runtime_options through _resume_session (fixes silent drop of
      instruction_directories/model/etc on resumed sessions)
    - Remove copilot_home from GitHubCopilotOptions (client-level setting only
      consumed at startup, not per-call)
    - Bump github-copilot-sdk from 1.0.0b1 to 1.0.0b2
    - Add test for instruction_directories override on resumed sessions
    - Update existing resume test to match new _resume_session signature
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add ClassSkill for class-based skill definitions (#5678)
    * Python: Add ClassSkill for class-based skill definitions
    
    Add ClassSkill abstract base class with decorator-based resource and script
    discovery, porting .NET's AgentClassSkill (PRs #5027 and #5183) to Python.
    
    - Add ClassSkill(Skill, ABC) with instructions abstract property, cached
      content/resources/scripts properties
    - Add @ClassSkill.resource and @ClassSkill.script static method decorators
      for auto-discovery of methods and properties
    - Extract _build_skill_content() and _create_resource_element() shared
      helpers from InlineSkill for reuse
    - Add _discover_marked_members() for scanning class hierarchies
    - Add _make_method_name() for Python-to-skill name conversion
    - Add class_based_skill sample (UnitConverterSkill)
    - Update mixed_skills sample with TemperatureConverterSkill
    - Add 58 new tests covering ClassSkill, decorator discovery, property
      resources, inheritance, kwargs forwarding, and duplicate detection
    - Export ClassSkill from agent_framework public API
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: replace try/except/continue with assignment to satisfy bandit B112
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * address PR review feedback
    
    - Walk cls.__mro__ in _discover_marked_members for inherited property resources
    - Use inspect.getattr_static for MRO-aware is_property check
    - Return defensive copies from resources/scripts properties
    - Raise TypeError on wrong decorator stacking order (@resource above @property)
    - Log warning instead of silently swallowing descriptor errors during discovery
    - Validate explicit name= at decoration time via _validate_member_name
    - Add tests for all of the above
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix temperature converter skill: make resource necessary for script
    
    Refactor TemperatureConverterSkill so the agent must read the
    formulas resource (factor/offset) before calling the script,
    aligning with the volume-converter pattern.
    
    - Resource: numeric factor/offset table instead of symbolic formulas
    - Script: generic linear transform (value * factor + offset)
    - Instructions: updated to reflect new workflow
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Remove bespoke Foundry toolbox helpers; standardize on MCP for toolbox consumption (#5671)
    * Remove Foundry toolbox helpers; standardize on MCP for toolbox consumption
    
    - Remove RawFoundryChatClient.get_toolbox() and its fetch_toolbox import
    - Remove fetch_toolbox, select_toolbox_tools, get_toolbox_tool_name,
      get_toolbox_tool_type, FoundryHostedToolType, ToolboxToolSelectionInput
      from agent_framework_foundry._tools
    - Remove ExperimentalFeature.TOOLBOXES from _feature_stage.py (no consumers)
    - Drop toolbox re-exports from agent_framework_foundry/__init__.py and
      agent_framework.foundry namespace
    - Update _sanitize_foundry_response_tool docstring to remove toolbox framing;
      sanitization logic itself is unchanged
    - Update _agent.py docstring: 'toolbox-fetched MCP' → 'hosted MCP'
    - Delete tests/test_toolbox.py (all tests covered removed helpers)
    - Update test_foundry_chat_client.py: rename/redoc tests that mentioned
      toolbox but test sanitization that remains
    - Delete foundry_chat_client_with_toolbox.py (bespoke toolbox API sample)
    - Delete foundry_toolbox_context_provider.py (relied on select_toolbox_tools)
    - Rename foundry_chat_client_with_toolbox_mcp.py →
      foundry_chat_client_with_toolbox.py (canonical MCP pattern)
    - Rewrite 04_foundry_toolbox/main.py to use MCPStreamableHTTPTool
    - Update provider/README, context_providers/README, 04_foundry_toolbox/README
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(samples): update 06_files sample to consume toolbox via MCP (#5670)
    
    Replace removed get_toolbox/select_toolbox_tools APIs with
    MCPStreamableHTTPTool, using allowed_tools=["code_interpreter"] to
    select only the code interpreter from the toolbox endpoint.
    
    Update .env.example and README to use FOUNDRY_TOOLBOX_ENDPOINT
    instead of TOOLBOX_NAME.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(foundry): remove non-existent toolbox helper APIs from README (#5670)
    
    Remove the 'fetch, optionally filter, and pass tools directly' pattern
    from the FoundryChatClient toolbox documentation, as select_toolbox_tools
    and get_toolbox were removed. Only the MCP endpoint pattern is documented.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(foundry): remove residual toolbox docstring references and reproduction report
    
    Remove REPRODUCTION_REPORT.md (workflow artifact that should not be committed),
    and update two remaining docstring references that still said 'toolbox reads'
    /'toolbox definition' after the toolbox helpers were removed.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Remove bespoke Foundry toolbox helpers; standardize on MCP for toolbox consumption
    
    Fixes #5670
    
    * fix(#5670): resolve toolbox endpoint from TOOLBOX_NAME fallback; add namespace regression tests
    
    - Add _resolve_toolbox_endpoint() helper in 04_foundry_toolbox/main.py and
      06_files/main.py that prefers FOUNDRY_TOOLBOX_ENDPOINT but falls back to
      deriving the MCP URL from FOUNDRY_PROJECT_ENDPOINT + TOOLBOX_NAME — fixing
      the startup KeyError when agents are deployed via azd provision (which injects
      TOOLBOX_NAME, not FOUNDRY_TOOLBOX_ENDPOINT).
    - Update 04_foundry_toolbox/.env.example to use FOUNDRY_TOOLBOX_ENDPOINT
      (consistent with 06_files).
    - Add TOOLBOX_NAME env var to 06_files/agent.yaml so deployed agents have it
      available for the fallback derivation.
    - Update both READMEs to document the two ways to supply the toolbox endpoint.
    - Add test_foundry_namespace_no_longer_exposes_toolbox_helpers() with negative
      assertions for FoundryHostedToolType, get_toolbox_tool_name,
      get_toolbox_tool_type, and select_toolbox_tools — guarding against accidental
      re-introduction of removed symbols.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(samples): fail fast on empty FOUNDRY_TOOLBOX_ENDPOINT; add unit tests
    
    Addresses review feedback for #5670:
    
    - In _resolve_toolbox_endpoint() (04_foundry_toolbox/main.py and
      06_files/main.py) change the walrus-operator check from a truthy
      test to an explicit 'is not None' guard.  An explicitly set empty
      string now raises ValueError immediately with a clear message
      instead of silently falling through to the fallback URL
      construction.
    
    - Add tests/samples/hosting/test_toolbox_endpoint.py covering both
      sample modules:
        (a) FOUNDRY_TOOLBOX_ENDPOINT set → returned as-is
        (b) FOUNDRY_TOOLBOX_ENDPOINT set to empty string → ValueError
        (c) fallback constructs URL from FOUNDRY_PROJECT_ENDPOINT + TOOLBOX_NAME,
            stripping trailing slashes
        (d) neither variable group set → KeyError
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback: remove extraneous test and docstring content
    
    - Remove test_foundry_namespace_no_longer_exposes_toolbox_helpers (no longer warranted)
    - Remove docstring from _agent.py _prepare_tools_for_openai (extraneous)
    - Trim _chat_client.py _prepare_tools_for_openai docstring to one-liner (toolbox references no longer relevant)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: remove remaining extraneous docstring from RawFoundryChatClient._prepare_tools_for_openai
    
    Address review comment on PR #5671: reviewer noted the description
    isn't warranted now that toolbox helpers have been removed. Matches
    the pattern in RawFoundryAgentChatClient which has no docstring.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: [Breaking] Restructure agent skills to use multi-source architecture (#5584)
    * migrate skills to multi source architecture
    
    * Fix ruff lint errors in skills module (ASYNC240, SIM108, E501)
    
    - Use anyio.Path for async file I/O in _FileSkillResource.read()
    - Use noqa: ASYNC240 for pure string os.path calls in async context
    - Restore pre-commit if/else pattern in InlineSkillScript.run()
    - Break long lines to fit 120-char limit in _skills.py and test_skills.py
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: collapse multi-line lambdas to single lines to fix pyright errors
    
    The pyright ignore comments only suppress errors on the same line, so
    multi-line lambdas left arguments on continuation lines uncovered.
    Collapse both lambdas to single lines matching the existing load_skill
    lambda pattern.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: replace untyped lambdas with typed inner functions to fix pyright errors
    
    Python lambdas cannot have type annotations, so pyright reports
    reportUnknownLambdaType and reportUnknownArgumentType errors that
    cannot be suppressed with inline ignore comments. Replace the
    lambdas for read_skill_resource and run_skill_script with typed
    inner async functions.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: address PR review feedback on docs and prompt template
    
    - Update with_prompt_template() docstring to document the
      {resource_instructions} placeholder requirement
    - Remove stray backslashes after {resource_instructions} and
      {runner_instructions} in DEFAULT_SKILLS_INSTRUCTION_PROMPT
    - Update subprocess_script_runner docstring to reflect
      FileSkillScript.full_path usage
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor: replace dict[str, Skill] with Sequence[Skill] in SkillsProvider
    
    Replace internal dict-based skills storage with Sequence[Skill] to
    eliminate silent duplicate overwrites and simplify the code. Add
    _find_skill helper for case-insensitive linear lookup.
    
    Also fix pyright errors in tests by adding isinstance assertions
    before accessing .function on SkillResource/SkillScript base types.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor: add read-time resource path validation in _FileSkillsSource
    
    Move security validation (path-traversal and symlink guards) for
    file-based skill resources into _FileSkillsSource, restoring the
    read-time checks that existed in main via _read_file_skill_resource.
    
    - Add _get_validated_resource_path static method on _FileSkillsSource
      that validates containment, existence, and symlink safety
    - _FileSkillsSource.get_skills() validates resource paths at discovery
      time via _get_validated_resource_path before passing to _FileSkillResource
    - Move _normalize_resource_path, _is_path_within_directory, and
      _has_symlink_in_path from module-level into _FileSkillsSource as
      static methods (only used there)
    - _FileSkillResource remains a simple path-to-content reader
    - Add tests for _get_validated_resource_path security checks
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: reject str/Path in SkillsProvider constructor to prevent str-as-Sequence ambiguity
    
    Since str is a Sequence, passing a path string to the source parameter
    would silently be treated as a sequence of characters instead of a
    file source. Add an explicit TypeError with a helpful message pointing
    callers to SkillsProvider.from_paths().
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR #5584 review feedback
    
    - Remove .NET reference from _FileSkillResource docstring
    - Fix inconsistent resource name example (references/FAQ.md -> references/FAQ)
    - Simplify SkillsProvider usage in code_defined_skill sample (pass single skill directly)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * remove skillsproviderbuilder
    
    * Update python/packages/core/agent_framework/_skills.py
    
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
    
    * fix: remove dead code and fix sync function call in InlineSkillResource.read()
    
    - Change await self.function() to self.function() for sync functions
      without **kwargs; async results are handled by inspect.isawaitable()
    - Remove unreachable raise ValueError since __init__ already validates
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * remove full_path unnecessary property
    
    * replace anyio with asyncio.to_thread for file I/O in _FileSkillResource
    
    Replace anyio.Path usage with asyncio.to_thread + pathlib.Path since
    anyio is not a direct dependency of core (transitive via mcp).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * simplify awaitable check to return directly
    
    Use 'return await result' instead of assigning then returning.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * address PR review feedback for skills refactoring
    
    - Replace anyio with asyncio.to_thread + pathlib.Path for file I/O
    - Simplify awaitable check to return directly
    - Remove unnecessary function None guard in InlineSkillResource.read()
    - Add assert for type narrowing on self.function
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * address PR review feedback for skills refactoring
    
    - Replace anyio with asyncio.to_thread + pathlib.Path for file I/O
    - Simplify awaitable checks to return directly
    - Remove unnecessary function None guard in InlineSkillResource.read()
    - Use typing.cast instead of assert for type narrowing
    - Add caching behavior note to SkillsProvider docstring
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor: move name/description from abstract properties to Skill.__init__
    
    Replace abstract properties for name and description on the Skill ABC
    with a base __init__ that validates and stores them as regular
    attributes. This simplifies custom Skill subclasses (only content
    remains abstract) and centralizes validation in the base class,
    consistent with SkillResource and SkillScript base classes.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
  • Python: information-flow control prompt injection defense (#5331)
    * Python: Information-flow control based prompt injection defense (#5024)
    
    * fides integration
    
    * documentation
    
    * documentation
    
    * documentation
    
    * human-approval on policy violation
    
    * numenous hyena 'works'
    
    * IFC based implementation
    
    * minor edits in documentation
    
    * rebasing the branch and running the email example
    
    * Add security tests for IFC middleware
    
    * Fix Role.TOOL NameError in approval handling
    
    * tiered labelling scheme
    
    * 3 tier labelling scheme in middleware
    
    * Adapt security middleware to list[Content] tool results
    
    * Refactor SecureAgentConfig as context provider and address Copilot review comments
    
    * Update FIDES docs to reflect context provider pattern and update code for ContextProvider rename
    
    * Fix security examples: use OpenAIChatClient instead of non-existent AzureOpenAIChatClient
    
    * Address PR review: consolidate security modules, remove ContentLineage, update docs
    
    * remove unrelated files
    
    * remove comment from _tools.py and rename decision file
    
    * Fix CI failures: Bandit B110, broken md links, hosted approval passthrough
    
    * apply template to decision doc 0024
    
    * minor fixes to decision doc 0024
    
    ---------
    
    Co-authored-by: Aashish <t-akolluri@microsoft.com>
    
    * Python: follow up FIDES security flow (#5330)
    
    * Python: follow up FIDES security flow
    
    Refine the secure approval path, mark the security classes with the FIDES experimental feature label, and clean up the related docs/tests. Also fix workspace-level validation regressions uncovered while running the full Python check suite.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: remove FIDES GitHub MCP sample
    
    Drop the GitHub MCP security sample from the FIDES follow-up branch while keeping the remaining security docs and samples intact.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review: fix paths and update FIDES implementation (#5352)
    
    * Python: updated import naming and comment from review (#5421)
    
    * updated import naming and comment from review
    
    * Add approval replay None call-id test
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Address PR 5331 comments and track sesssion while calling Agent in email_security_example (#5446)
    
    * Address PR review: fix paths and update FIDES implementation
    
    * Address PR comments and add session tracking in email example in samples
    
    * Fix session creation and resolve merge conflict in docstring example
    
    * Resolve merge conflict in docstring example
    
    * Python: add test for empty-message pruning in approval result replacement (#5617)
    
    Adds test coverage for the second-pass logic in
    `_replace_approval_contents_with_results` that removes messages whose
    `contents` list becomes empty after first-pass content removal.
    
    Addresses review comment on PR #5331:
    https://github.com/microsoft/agent-framework/pull/5331#discussion_r3129039445
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: shrutitople <shruti.tople@gmail.com>
    Co-authored-by: Aashish <t-akolluri@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix hyperlight WasmSandbox cross-thread Drop and harden hosted-agent sample (#5603)
    * update hyperlight to beta and move samples, add hosted agent sample
    
    * Python: Fix hyperlight WasmSandbox cross-thread Drop and harden sample
    
    Root cause: when a worker-side closure raised, the exception's __traceback__
    retained frame locals that included the partially constructed PyO3 sandbox.
    Future.result() re-raised that exception on the caller thread, and when the
    caller's exception was eventually GC'd the frame locals were released
    off-thread, dec_ref'ing the unsendable sandbox from the wrong thread and
    tripping the PyO3 panic
    '_native_wasm::WasmSandbox is unsendable, but is being dropped on another thread'.
    
    Fix:
    * Add _SandboxWorker._run_on_worker which catches every exception on the
      worker, drops __traceback__ there, deletes the original exception, and
      re-raises a fresh instance on the caller thread. initialize and execute
      route through it; dispose keeps its bare-submit semantics.
    * Add an opt-in diagnostic module _drop_diagnostic (no-op unless
      HYPERLIGHT_TRACE_DROPS=1) that installs a sys.unraisablehook and dumps
      owner-thread + per-thread stacks on any future cross-thread unsendable
      Drop. Useful for triaging similar PyO3 regressions.
    * Tests: cross-thread invocation, traceback-leak isolation, _SandboxEntry
      attribute-shape check, and a stale-reference stress test driven through
      asyncio.to_thread.
    
    Sample (samples/04-hosting/foundry-hosted-agents/responses/06_hyperlight_codeact):
    * Dockerfile installs agent-framework-* from in-tree source with python/ as
      build context so unreleased fixes can be validated end-to-end.
    * call_server.py pins the Responses API version.
    * main.py enables include_detailed_errors=True so future tool failures
      surface the actual exception text instead of a bare 'Error: Function
      failed.' string.
    * README.md documents the in-tree-package build and the Hyperlight
      hypervisor requirement (/dev/kvm on Linux, MSHV on Windows). Hosted
      environments without hypervisor passthrough surface 'No Hypervisor was
      found for Sandbox'; this is a hosting constraint, not a hyperlight bug.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: remove _drop_diagnostic from hyperlight package
    
    The diagnostic module was useful while bisecting the cross-thread Drop bug,
    but it is no longer needed now that _SandboxWorker._run_on_worker prevents
    the panic at the source.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: address PR review feedback on hyperlight
    
    - Use lazy agent_framework.hyperlight import in sample main.py.
    - Env-driven endpoint (FOUNDRY_AGENT_ENDPOINT) in call_server.py; remove personal URLs.
    - Align agent.yaml model deployment with manifest (gpt-4.1-mini).
    - Tighten Dockerfile requirements guard; drop dangling deploy.ps1 reference.
    - Preserve exception args when sanitizing tracebacks in _run_on_worker.
    - Add public _SandboxWorker.is_alive(); update test to avoid private attr.
    - Add namespace coverage tests for agent_framework.hyperlight lazy loader.
    - Add prominent note: Foundry hosted-agent runtime does not yet support
      Hyperlight (no hypervisor exposed); container works locally with /dev/kvm.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: bump hyperlight-sandbox dependencies to 0.4.x
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: renumber hyperlight codeact sample to 08
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Coerce worker exception args to strings for cross-thread safety
    
    Stringify exc.args on the worker thread before propagating, so any
    PyO3 unsendable object captured in args (e.g. via a caller-supplied
    callback or underlying SDK) cannot be Dropped on the calling thread.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * moved sample
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Support GPT-5 verbosity option and restore Foundry agent_reference (#5619)
    * Python: Support GPT-5 verbosity option and restore Foundry agent_reference
    
    Adds verbosity as a typed Literal["low","medium","high"] field on
    OpenAIChatOptions (Responses API) and OpenAIChatCompletionOptions (Chat
    Completions API), set in the same way as the existing reasoning options.
    For the Responses API, top-level verbosity is translated to the nested
    text.verbosity shape the OpenAI service expects. The same field flows
    through to FoundryChatClient via the existing FoundryChatOptions alias.
    
    Also fixes #5582: PR #5447 removed the agent_reference injection from
    RawFoundryAgentChatClient._prepare_options, so first-turn calls against
    a Foundry Prompt Agent went out without model and without agent_reference
    and were rejected by the Responses API with "Missing required parameter:
    'model'". Restores the injection on the non-preview path
    (allow_preview=False) and adds a guard test that asserts the preview
    path does not inject agent_reference, since the preview SDK injects it
    via project_client.get_openai_client(agent_name=...).
    
    Closes #5516
    Closes #5582
    
    * Python: Address Copilot review on PR #5619
    
    - Foundry verbosity sample docstring: replace the misleading "set deployment
      name on model=" instruction with the actual env-var pattern the sample relies
      on (FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL).
    - _build_agent_reference docstring: clarify the helper is used for both
      Prompt Agents and HostedAgents on the non-preview path.
    - Add a Responses API test that locks in the documented precedence rule:
      when both top-level verbosity and text["verbosity"] are supplied, the
      top-level value wins.
    
    * Python: Drop redundant Foundry verbosity sample and list OpenAI sample in README
    
    - Remove samples/02-agents/providers/foundry/foundry_chat_client_verbosity.py
      per review feedback. The verbosity functionality is identical across the
      OpenAI and Foundry clients (FoundryChatOptions is an alias of
      OpenAIChatOptions), so a single sample on the OpenAI side is sufficient.
    - Add the new client_verbosity.py entry to the OpenAI samples README.
  • Python: Document that W3C trace context injection does not apply to Foundry hosted/toolbox MCP tools (#5580)
    * docs: clarify MCP trace-context propagation scope for hosted/toolbox tools (#5547)
    
    Automatic W3C trace-context injection via params._meta applies only to
    MCP sessions opened by the agent process (MCPStreamableHTTPTool,
    MCPStdioTool, MCPWebsocketTool).  Hosted MCP tools
    (FoundryChatClient.get_mcp_tool) and toolbox-fetched tools
    (FoundryChatClient.get_toolbox) execute inside the Foundry agent service
    runtime; the framework never issues the tools/call for those and
    therefore cannot inject traceparent/tracestate.  The previous wording
    ("for all transports") implied coverage that does not exist.
    
    The updated section:
    - removes the inaccurate "for all transports" claim
    - adds a Scope paragraph naming the three client-opened transports that
      are covered
    - explicitly states that propagation across the agent-to-toolbox-to-MCP
      boundary is the responsibility of the Foundry service runtime
    - documents the workaround (use MCPStreamableHTTPTool directly) for
      users who need end-to-end distributed tracing today
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs: broaden MCP _meta scope note to cover all provider-managed transports (#5547)
    
    - List OpenAIChatClient.get_mcp_tool() and AnthropicClient.get_mcp_tool()
      alongside FoundryChatClient.get_mcp_tool() as hosted/provider-managed
      exceptions; restricting the carve-out to Foundry was misleading for
      readers using other providers
    - Fix get_toolbox() wording: use 'await client.get_toolbox(...)' and note
      that toolbox.tools is passed into Agent(tools=...) so it reads as an
      async instance method call, not a static/class method call
    - Add parenthetical '(or any other client-opened MCPTool subclass)' to
      future-proof the list of covered transports
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs: add GeminiChatClient to MCP scope note and add learn-site observability doc (#5547)
    
    - Add GeminiChatClient.get_mcp_tool(...) to the hosted/provider-managed
      list in the MCP trace propagation scope note; Gemini's get_mcp_tool()
      returns a types.Tool with an McpServer entry executed by the Gemini
      service runtime, so it belongs alongside FoundryChatClient,
      OpenAIChatClient, and AnthropicClient in that list.
    - Create docs/features/observability/README.md as the learn-site
      documentation surface for observability, covering telemetry setup and
      MCP trace propagation with the same scope note (including
      GeminiChatClient) so that both doc surfaces are consistent.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove unneeded observability docs README
    
    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: Enforce approval_mode in Claude and GitHub Copilot agents (#5562)
    * Python: Enforce approval_mode in Claude and GitHub Copilot agents
    
    Tools declared with approval_mode="always_require" were bypassed by the
    ClaudeAgent and GitHubCopilotAgent because their SDK-managed tool-calling
    loops invoke FunctionTool.invoke() directly via package-supplied handlers,
    skipping the standard _try_execute_function_calls approval gate.
    
    Per discussion on #5494, the fix lives in the agents (not in FunctionTool):
    any flag added to the tool itself can be spoofed by code with the same
    level of access, so the security boundary is the agent that owns the
    tool-calling loop.
    
    - Add on_function_approval option to ClaudeAgentOptions and
      GitHubCopilotOptions. Callback receives a FunctionCallContent describing
      the pending call and returns bool (sync or async).
    - Gate FunctionTool.invoke() inside each agent's existing tool-handler
      closure when approval_mode == "always_require". Default policy is deny;
      callbacks that raise also deny safely.
    - Deny path returns a tool-error to the model (Claude: text content;
      Copilot: ToolResult(result_type="failure", error="approval_denied"))
      so the LLM can react gracefully instead of silently failing.
    - Tests for both agents covering: deny by default, sync False, sync True,
      async True, callback-raises -> deny, no-op for never_require tools.
    - Samples demonstrating sync, async, and deny-by-default flows for both
      agents.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review: preserve empty arg dicts, reject runtime approval override
    
    - _resolve_function_approval no longer collapses {} into None when building
      the FunctionCallContent passed to the callback (Claude + Copilot).
    - Claude _apply_runtime_options and Copilot _run_impl/_stream_updates now
      raise ValueError if on_function_approval is supplied via per-run options,
      instead of silently ignoring it. Approval policy must be set at agent
      construction time.
    - Drop unnecessary # type: ignore[attr-defined] on Content.name/.arguments
      in samples (Content is a unified class with both attributes defined).
    - Add regression tests for the new runtime-options validation.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * warning when non callback handler and approval needed
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: update FoundryAgent for hosted agent sessions (#5447)
    * fixes to FoundryAgent to connect to new hosted agents
    
    Co-authored-by: Copilot <copilot@github.com>
    
    * fix mypy
    
    Co-authored-by: Copilot <copilot@github.com>
    
    * Python: remove Foundry service session helpers
    
    Remove the public hosted-agent service session CRUD helpers from FoundryAgent and drop the related feature-stage inventory entry.
    
    Update the hosted-agent sample to create and delete service sessions directly through the preview AIProjectClient APIs, and tighten a few test harnesses surfaced by full workspace validation.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix from merge
    
    * fix hosted env detection
    
    Co-authored-by: Copilot <copilot@github.com>
    
    * reverted sample update
    
    * fix tests and code
    
    Co-authored-by: Copilot <copilot@github.com>
    
    * remove aenter
    
    * skipping some tests
    
    Co-authored-by: Copilot <copilot@github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add OpenTelemetry integration for GitHubCopilotAgent (#5142)
    * Python: Add OpenTelemetry integration for GitHubCopilotAgent
    
    - Split GitHubCopilotAgent into RawGitHubCopilotAgent (core, no OTel) and
      GitHubCopilotAgent(AgentTelemetryLayer, RawGitHubCopilotAgent) with tracing
    - Add default_options property to expose model for span attributes
    - Export RawGitHubCopilotAgent from all public namespaces
    - Add github_copilot_with_observability.py sample and update README
    
    * Python: Fix OTEL_SERVICE_NAME default in GitHub Copilot README
    
    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
    
    * Python: Add unit tests for RawGitHubCopilotAgent.default_options property
    
    * Python: Address review feedback on GitHubCopilotAgent OTel integration
    
    - Add middleware param to GitHubCopilotAgent.run() overloads so per-call
      middleware is explicitly forwarded through AgentTelemetryLayer
    - Remove github_copilot_with_observability.py sample per feedback; replace
      with inline snippet + link to observability samples in README
    
    * Python: Address review feedback on log_level and session kwargs typing
    
    - Add middleware param to RawGitHubCopilotAgent.run() overloads for interface
      compatibility with AgentTelemetryLayer
    - Fix import in README observability snippet to use agent_framework.github
    
    * Python: Add AgentMiddlewareLayer to GitHubCopilotAgent MRO
    
    Follow FoundryAgent pattern: AgentMiddlewareLayer runs outside the telemetry
    span so middleware execution time is not captured in traces. Overloads removed
    as AgentMiddlewareLayer.run() handles dispatch via MRO.
    
    * Python: Add explicit __init__ to GitHubCopilotAgent for auto-complete and docstrings
    
    * Python: Address review feedback on middleware warning and test assertions
    
    - Add assert "timeout" not in opts to test_default_options_includes_model_for_telemetry
      to document the intentional asymmetry where timeout is extracted into _settings
      and not returned in default_options.
    - Replace silent del middleware with a logged warning when per-run middleware is
      passed to RawGitHubCopilotAgent, making it clear that the GitHub Copilot SDK
      handles tool execution internally and chat/function middleware cannot be injected.
    
    * Python: Use Self for __aenter__ return type in RawGitHubCopilotAgent
    
    Address review feedback: use typing.Self (3.11+) / typing_extensions.Self
    (3.10) for __aenter__ so subclasses like GitHubCopilotAgent get the correct
    return type from async context manager usage.
    
    ---------
    
    Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
  • Python: fix(foundry): reconcile toolbox hosted-tool payloads with Responses API (#5414)
    * fix(foundry): reconcile toolbox hosted-tool payloads with Responses API
    
    * docs(foundry): update create_sample_toolbox docstring to reflect all tools created
  • Python: Fix OpenAI Responses streaming to propagate created_at from final response.completed event (#5382)
    * Fix streaming response losing created_at from response.completed event (#5347)
    
    The streaming path in _parse_chunk_from_openai did not extract created_at
    from the response.completed event, unlike the non-streaming path in
    _parse_responses_response. This caused durabletask persistence warnings
    when created_at was None.
    
    Extract created_at in the response.completed case and pass it to the
    returned ChatResponseUpdate.
    
    Also fix pre-existing pyright errors for optional orjson import in sample
    files.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix orjson import suppression to use pyright instead of mypy (#5347)
    
    Replace `# type: ignore[import-not-found]` with
    `# pyright: ignore[reportMissingImports]` on optional orjson imports
    in conversation sample files, matching the repo's Pyright strict
    configuration.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Foundry hosted agent V2 (#5379)
    * Python: Wrapper + Samples 1st (#5177)
    
    * Experiment
    
    * Update dependency and add non streaming
    
    * Add more samples
    
    * Rename samples
    
    * Add invocations
    
    * Comments 1
    
    * Comments 2
    
    * Comments 3
    
    * Improve README
    
    * Add local shell sample
    
    * WIP: Add eval and memory samples
    
    * Update user agent prefix
    
    * Update user agent prefix doc
    
    * Update dependency (#5215)
    
    * Add tests and more content types (#5235)
    
    * Add tests
    
    * fix tests and sample
    
    * Fix formatting
    
    * Remove function approval contents
    
    * Python: Refine samples and upgrade packages (#5261)
    
    * Refine samples and upgrade pacakges
    
    * Upgrade to a new package that fixes a bug
    
    * Update model env var
    
    * Move samples (#5281)
    
    * Python: Upgrade agentserver packages (#5284)
    
    * Upgrade agentserver packages
    
    * Fix new types
    
    * Python: Add special handling for workflows (#5298)
    
    * Add special handling for workflows
    
    * Address comments
    
    * Improve samples (#5372)
    
    * Python: Add more types (#5378)
    
    * Add more type supports
    
    * Upgrade packages
    
    * Remove TODOs in README
    
    * Fix README
    
    * Comments and mypy
    
    * User agent scoped
    
    * Fix README
    
    * Fix pre commit
    
    * Fix pre commit 2
    
    * Fix pre commit 3
    
    * Fix pre commit 4
    
    * Fix pre commit 5
    
    * Fix pre commit 6
    
    * Add azure-monitor-opentelemetry to dev deps
    
    Fixes Samples & Markdown CI failure. The PR's new transitive dep on
    azure-monitor-opentelemetry-exporter (via azure-ai-agentserver-core) makes
    pyright resolve the azure.monitor.opentelemetry namespace, flipping the
    check_md_code_blocks diagnostic for `configure_azure_monitor` from
    reportMissingImports (filtered) to reportAttributeAccessIssue (not filtered).
    Installing the umbrella azure-monitor-opentelemetry package in dev makes
    pyright resolve the symbol correctly, matching the install guidance the
    observability README already gives users.
    
    ---------
    
    Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
  • Python: Add support for Foundry Toolboxes (#5346)
    * Add support for the Foundry Toolbox in MAF
    
    Introduces a Foundry Toolbox integration: FoundryChatClient gains a
    get_toolbox() helper plus select_toolbox_tools(), normalize_tools in
    the core package flattens tool-collection wrappers (ToolboxVersionObject
    and generic iterables, while leaving Pydantic BaseModel instances
    alone), and the new agent_framework.foundry namespace re-exports the
    toolbox helpers. Ships with unit tests, a sample, and a design doc.
    
    azure-ai-projects is pinned to the public >=2.0.0,<3.0 range and the
    lockfile resolves from public PyPI. The toolbox test module skips when
    Toolbox* types are unavailable so CI stays green until the public 2.1.0
    SDK lands. OMC tooling directories (.omc/, .omx/) are gitignored.
    
    * Update to latest azure ai projects package
    
    * Improve sample
    
    * Rename ADR to 0025
    
    * Update ADR
    
    * Apply suggestion from @alliscode
    
    Co-authored-by: Ben Thomas <ben.thomas@microsoft.com>
    
    * Improve samples
    
    * Update test
    
    ---------
    
    Co-authored-by: Ben Thomas <ben.thomas@microsoft.com>
  • Python: Add Hyperlight CodeAct package and docs (#5185)
    * initial work on code_mode
    
    * updated samples
    
    * updates to codeact
    
    * udpated codeact
    
    * Draft CodeAct ADR and sample updates
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * initial implementation and adr and feature
    
    * Python: Limit Hyperlight wasm backend to Python <3.14
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Fix CI for Hyperlight CodeAct PR
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Run Hyperlight integration when available
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Address Hyperlight review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Simplify Hyperlight file mount inputs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Accept Path host paths in Hyperlight mounts
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Fix Hyperlight mount typing for CI
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * temp run integration test
    
    * Python: Strengthen Hyperlight real sandbox tests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * added additional tests
    
    * Python: Simplify Hyperlight CodeAct API
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * set tests as non-integration
    
    * Retry Hyperlight allowed-domain registration
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Gate Hyperlight integration tests by runtime support
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix Hyperlight skip test on Python 3.14
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Delay Hyperlight runtime probe until test execution
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Relax Hyperlight Windows integration stdout assertion
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Scan Hyperlight output directory for artifacts
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Retry Hyperlight output artifact collection
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Harden Hyperlight integration output assertions
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Retry Hyperlight read-back check in integration test
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Simplify Hyperlight integration write assertion
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Avoid pathlib in Hyperlight integration sandbox
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Use socket network check in Hyperlight sandbox
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Replace blocked Azure AI Search blog link
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Clarify Hyperlight guest stdlib limits
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Use _socket in Hyperlight integration sandbox
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Handle Hyperlight mounted file paths
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Broaden Hyperlight sandbox path fallbacks
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Search Hyperlight guest mounts recursively
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Split Hyperlight mount coverage
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Split Hyperlight live network tests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix Hyperlight file-write test on Windows
    
    Enable the sandbox filesystem by providing a workspace_root so
    /output is mounted. Remove os.path.exists assertion (unsupported
    in WASM guest) and fix Content data assertion to use .uri.
    Skip the network integration test on Windows where the WASM
    sandbox lacks the encodings.idna codec.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review: ADR intro, manual wiring sample, doc clarifications
    
    - Add CodeAct introduction section to ADR for unfamiliar readers
    - Clarify 'less runtime efficient' con with specific overhead description
    - Add note in Python impl doc clarifying ADR vs impl doc split
    - Explain why before_run hooks must be per-run (CRUD, concurrency, approval)
    - Rename code_interpreter variable to codeact in E2E sample
    - Add manual static wiring sample (codeact_manual_wiring.py)
    - Add 'when to use which pattern' guidance to samples README
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR #5185 review comments and add .NET CodeAct design doc
    
    - Fix async callback: _make_sandbox_callback returns sync wrapper with
      thread + asyncio.run() bridge (was broken with real Wasm FFI)
    - Fix stale output: clear output_dir before each sandbox.run() call
    - Fix blocking event loop: _run_code now async with asyncio.to_thread()
    - Revert _agents.py options['tools'] injection (unnecessary; provider
      uses context.extend_tools())
    - Revert SessionContext.options docstring back to read-only
    - Add real-sandbox test fixtures (shared/restored/fresh)
    - Add 8 new real-sandbox tests for callback round-trip, stale output,
      event loop non-blocking, basic execution, stdout/stderr, errors,
      snapshot/restore, and tool registration
    - Add comprehensive .NET HyperlightCodeActProvider design document
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Update hyperlight README with code snippets and remove Public API section
    
    Replace bare export list with Quick Start code examples covering the
    context provider, standalone tool, manual static wiring, and file
    mounts / network access patterns.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: add experimental file history provider (#5248)
    * add experimental file history provider
    
    * Improve file history provider writes
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * typo
    
    * cleanup
    
    * cleanup
    
    * fix in readme
    
    * added security messages
    
    * Refine file history provider locking
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * added additional sample
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Migrate GitHub Copilot package to SDK 0.2.x (#5107)
    * Python: Migrate GitHub Copilot package to SDK 0.2.x
    
    Replace all imports from the non-existent copilot.types module with
    correct SDK 0.2.x module paths (copilot.session, copilot.client,
    copilot.tools, copilot.generated.session_events). Fix PermissionRequest
    attribute access from dict-style .get() to dataclass attribute access.
    Add OTel telemetry support to Copilot samples via configure_otel_providers
    and document new telemetry environment variables in samples README.
    
    * Python: Fix remaining copilot.types import in sample validation script
    
    * Python: Include model in default_options for telemetry span attributes
    
    * Python: Address review feedback on log_level and session kwargs typing
    
    * Python: Scope PR to SDK 0.2.x migration only, remove net-new OTel features
    
    - Remove RawGitHubCopilotAgent split and AgentTelemetryLayer inheritance
    - Remove TelemetryConfig plumbing and OTLP/file telemetry settings
    - Remove configure_otel_providers() calls from samples
    - Remove telemetry env var rows from samples README
    - Retain only: import path fixes, PermissionRequest attribute access fix,
      log_level default fix, session kwargs typed fix, dependency pin
    
    * Python: Update tests for SDK 0.2.x API changes
    
    - SubprocessConfig replaces CopilotClientOptions dict
    - create_session and resume_session now use keyword args
    - send and send_and_wait take plain string prompt instead of MessageOptions
    - on_permission_request is always required; deny-all fallback replaces omission
    
    * Python: Pin github-copilot-sdk to >=0.2.0,<=0.2.0
    
    Tighten the upper bound from <0.3.0 to <=0.2.0 to avoid pulling in 0.2.1+
    which has breaking API changes relative to 0.2.0. The lower bound stays at
    >=0.2.0 since this migration requires the 0.2.x import paths; 0.1.x would
    fail at import time.
    
    * Python: Pin github-copilot-sdk to >=0.2.1,<=0.2.1
    
    ---------
    
    Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
  • Python: Stop emitting duplicate reasoning content from OpenAI response.reasoning_text.done and response.reasoning_summary_text.done events (#5162)
    * Fix reasoning text done events duplicating streamed delta content (#5157)
    
    The OpenAI Responses API sends both reasoning_text.delta (incremental
    chunks) and reasoning_text.done (full accumulated text) events. The
    chat client was emitting Content for both, causing ag-ui to append the
    full done text onto already-accumulated delta text, producing
    duplicated reasoning output.
    
    Stop emitting Content for reasoning_text.done and
    reasoning_summary_text.done events, matching how output_text.done is
    already handled (not emitted). The deltas contain all the content;
    the done event is redundant.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(openai): emit reasoning done content as fallback when no deltas observed (#5157)
    
    Address PR review feedback:
    - Track item_ids that received reasoning deltas via seen_reasoning_delta_item_ids set
    - Emit content from done events only when no deltas were received for the
      item_id, preventing silent content loss on stream resumption
    - Add comment documenting code_interpreter done event asymmetry
    - Replace redundant ag-ui test with deduplication-focused test
    - Add integration test for delta+done sequence in OpenAI chat client tests
    - Add fallback path tests for done events without preceding deltas
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #5157: Python: [Bug]: "type": "response.reasoning_text.delta" and "response.reasoning_text.done" both get exposed as "text_reasoning"
    
    * Fix AG-UI reasoning streaming to use proper Start/End pattern (#5157)
    
    _emit_text_reasoning now follows the same streaming pattern as _emit_text:
    - Emits ReasoningStartEvent/ReasoningMessageStartEvent only on the first
      delta for a given message_id
    - Emits only ReasoningMessageContentEvent for subsequent deltas
    - Defers ReasoningMessageEndEvent/ReasoningEndEvent until
      _close_reasoning_block is called (on content type switch or end-of-run)
    
    This produces the correct protocol pattern:
      ReasoningStartEvent
        ReasoningMessageStartEvent
        ReasoningMessageContentEvent(delta1)
        ReasoningMessageContentEvent(delta2)
        ReasoningMessageEndEvent
      ReasoningEndEvent
    
    Instead of wrapping every delta in a full Start→End sequence.
    
    Backward compatibility is preserved: calling _emit_text_reasoning without
    a flow argument still produces the full sequence per call.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix import ordering lint error in AG-UI test file (#5157)
    
    Move inline import of TextMessageContentEvent to the top-level import
    block and ensure alphabetical ordering to satisfy ruff I001 rule.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix mypy error: rename loop variable to avoid type conflict with WorkflowEvent
    
    The 'event' variable was already typed as WorkflowEvent[Any] from the
    async for loop at line 590. Reusing it in the _close_reasoning_block
    loop (which returns list[BaseEvent]) caused an incompatible assignment
    error. Renamed to 'reasoning_evt' to avoid the conflict.
    
    Fixes #5162
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback for #5157: review comment fixes
    
    * narrow test result reporting to explicit pytest JUnit XML
    
    * Fix test args
    
    * Fix pytest-results-action in merge workflow and remove committed test artifacts
    
    Apply the same JUnit XML fix from python-tests.yml to python-merge-tests.yml:
    add --junitxml=pytest.xml to all test commands and narrow the results action
    path from ./python/**.xml to ./python/pytest.xml. Also remove accidentally
    committed pytest.xml and python-coverage.xml and add them to .gitignore.
    
    ---------
    
    Co-authored-by: Copilot <copilot@github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add Cosmos DB NoSQL Checkpoint Storage for Python Workflows (#4916)
    * Add CosmosCheckpointStorage for Python workflow checkpointing
    
    Add native Cosmos DB NoSQL support for workflow checkpoint storage in the
    Python agent-framework-azure-cosmos package, achieving parity with the
    existing .NET CosmosCheckpointStore.
    
    New files:
    - _checkpoint_storage.py: CosmosCheckpointStorage implementing the
      CheckpointStorage protocol with 6 methods (save, load, list_checkpoints,
      delete, get_latest, list_checkpoint_ids)
    - test_cosmos_checkpoint_storage.py: Unit and integration tests
    - workflow_checkpointing.py: Sample demonstrating Cosmos DB-backed
      workflow checkpoint/resume
    
    Auth support:
    - Managed identity / RBAC via Azure credential objects
      (DefaultAzureCredential, ManagedIdentityCredential, etc.)
    - Key-based auth via account key string or AZURE_COSMOS_KEY env var
    - Pre-created CosmosClient or ContainerProxy
    
    Key design decisions:
    - Partition key: /workflow_name for efficient per-workflow queries
    - Serialization: Reuses encode/decode_checkpoint_value for full Python
      object fidelity (hybrid JSON + pickle approach)
    - Container auto-creation via create_container_if_not_exists
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Adding cosmos checkpointer
    
    * Resolving comments
    
    * Fixing builds
    
    * Adding sample for history provider and checkpoint storage
    
    * Resolving comments
    
    * fixing builds
    
    * Resolving comments
    
    ---------
    
    Co-authored-by: Aayush Kataria <aayushkataria@Aayushs-MacBook-Pro-2.local>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
  • Python: Adds sample documentation for two separate Neo4j context providers for retrieval and memory (#4010)
    * Python: Adds sample documentation for two separate Neo4j context providers for retrieval and memory
    
    * adding pypi links
    
    * adding dotnot examples
    
    * adding dotnot examples
    
    * merge upstream samples
    
    * fixing docs
    
    * fix relative paths
    
    ---------
    
    Co-authored-by: Ben Lackey <ben.lackey@neo4j.com>
  • Python: [BREAKING] update to v1.0.0 (#5062)
    * updates to final deprecated pieces and versions
    
    * fix mypy
    
    * fix readme links
  • Python: [BREAKING] Python: move Azure AI embeddings to Foundry (#5056)
    * renamed AzureAIINferenceEmbeddings and lazy load azure-cosmos and env var rename
    
    * updated coverage
    
    * fix readme
  • Python: Fix server_tool_use input_json_delta handling and improve Anthropic samples (#5050)
    * Fix server_tool_use input_json_delta handling and improve Anthropic samples
    
    - Fix: Skip input_json_delta for server_tool_use content blocks in AnthropicClient streaming. Server-managed tools (e.g., skills with code interpreter) were producing Content.from_function_call(name='') entries that caused Anthropic API 400 errors on subsequent turns.
    
    - Samples: Add dotenv loading and environment variable documentation to Anthropic Claude samples (MCP, permissions, session, shell, tools, URL, skills).
    
    * Add regression test for server_tool_use + input_json_delta skip behavior
    
    Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/7c68dcb2-b577-4e36-b423-664b8fe3ac1d
    
    Co-authored-by: chetantoshniwal <255221507+chetantoshniwal@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: chetantoshniwal <255221507+chetantoshniwal@users.noreply.github.com>
  • Python: Move workflow-samples and agent-samples under declarative-agents directory (#5011)
    * Move workflow-samples and agent-samples under declarative-agents and update all references
    
    Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/f70f7d19-9256-4eec-b7db-28007d74440c
    
    Co-authored-by: sphenry <6749825+sphenry@users.noreply.github.com>
    
    * Fix relative paths in README files inside moved directories
    
    Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/f70f7d19-9256-4eec-b7db-28007d74440c
    
    Co-authored-by: sphenry <6749825+sphenry@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: sphenry <6749825+sphenry@users.noreply.github.com>
    Co-authored-by: Shawn Henry <shahen@microsoft.com>
  • Python: Fix SK migration samples (#5047)
    * Fix SK migration samples
    
    * Fix env vars for SK
    
    * Hard code model for sheel tool samples
  • Python: Fix broken samples and add missing READMEs (#5038)
    * Python: Fix broken samples and add missing READMEs
    
    - simple_context_provider: move instructions kwarg into options dict
    - suspend_resume_session: use OpenAIChatCompletionClient for in-memory demo
    - foundry_chat_client_with_hosted_mcp: move store kwarg into options dict
    - Add README.md for context_providers and conversations sample folders
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Fix additional sample issues in context_providers
    
    - mem0_basic: send preferences query before sleep so Mem0 can learn them,
      print result from new session recall
    - mem0_sessions: add session for multi-turn conversation in agent-scoped
      example, remove user_id from agent-scoped provider (Mem0 API stores
      memories without user_id when agent_id is provided), use single message
      for storing preferences
    - redis_basics: print retrieved context messages instead of raw object
    - redis_sessions: add missing load_dotenv() call
    - redis_basics/redis_sessions: fix docstrings referencing wrong client type
    - azure_redis_conversation: replace duplicate copyright with load_dotenv()
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: Fix broken link in declarative README
    
    openai_responses_agent.py was renamed to openai_agent.py
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: updated declarative samples and handling of non-pydantic response formats (#5022)
    * updated declarative samples and handling of non-pydantic response formats
    
    * fixed from comments
    
    * update docstring
  • Python: [BREAKING] Standardize model selection on model (#4999)
    * Refactor Anthropic model option and provider clients
    
    Rename the Anthropic client model option from model_id to model, add provider-specific Anthropic wrappers for Foundry, Bedrock, and Vertex, and expose them through the Anthropic, Foundry, Amazon, and Google namespaces. Update core option handling, docs, samples, and tests accordingly.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix Anthropic skills sample typing
    
    Cast the Anthropic beta client to Any in the skills sample so the pre-commit sample pyright check no longer fails on beta skills and files endpoints that are not exposed by the current SDK stubs.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * undo sample mypy
    
    * Retry CI after transient external failures
    
    Retrigger PR validation after an unrelated Copilot review workflow SAML failure and a transient external tau2 git fetch failure in the Windows Python test setup.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback on model option merging
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address Anthropic compatibility review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * moved all to `model`
    
    * fixes for azure ai search
    
    * Python: standardize remaining sample env var names
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python: fix foundry-local pyright compatibility
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * updated env vars in cicd
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Fix observability samples (#5016)
    * Fix observability samples
    
    * Update python/samples/02-agents/observability/configure_otel_providers_with_parameters.py
    
    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
    
    * Update python/samples/02-agents/observability/agent_observability.py
    
    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
    
    * Update python/samples/02-agents/observability/agent_observability.py
    
    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
  • Python: [BREAKING] update context provider APIs, middleware, and per-service-call history persistence (#4992)
    * Rename provider base APIs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Allow provider-added chat and function middleware
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Simulate service-stored history per model call
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix typing regressions in CI
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix response ID suppression review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Rename per-service-call history persistence APIs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address context persistence review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Stabilize markdown sample docs
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Persist service continuation state per call
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: fixed middleware samples (#5026)
    * fixed samples
    
    * small update to explanation
    
    * add snippet fix on root readme
  • Python: updated azure ai inference sample (#5028)
    * updated azure ai inference sample
    
    * openai multimodel fix
    
    * update language