Merge feature/azure-ai-projects/vnext into Main. Do not complete this PR! - #47803
Merge feature/azure-ai-projects/vnext into Main. Do not complete this PR!#47803dargilco wants to merge 31 commits into
feature/azure-ai-projects/vnext into Main. Do not complete this PR!#47803Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the azure-ai-projects package version to 2.4.0 and adds a new 2.4.0 section to the changelog to begin tracking changes for that version.
Changes:
- Added a new
## 2.4.0 (Unreleased)changelog section with subsections. - Bumped the library version constant from
2.3.0to2.4.0.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| sdk/ai/azure-ai-projects/CHANGELOG.md | Adds a new 2.4.0 (Unreleased) entry scaffold (currently with placeholder bullets). |
| sdk/ai/azure-ai-projects/azure/ai/projects/_version.py | Updates the package version constant to 2.4.0. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 25 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
sdk/ai/azure-ai-projects/tsp-location.yaml:22
- These paths do not exist at the pinned
fca510e0...commit. That tree still exposesopenai-conversations,openai-evaluations, andopenai-responsesdirectly undersrc, sotsp-client updatecannot resolve these additional directories. Keep the paths aligned with the pinned commit (or pin a commit that contains the nested layout).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 25 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
sdk/ai/azure-ai-projects/CHANGELOG.md:11
- The 2.4.0 release notes still hide the actual breaking API changes behind a placeholder. This API surface removes
ReminderPreviewTooland introduces/narrows several public request types, so consumers need concrete migration information before this stable release ships. Replace this placeholder with the breaking changes, and remove any empty placeholder sections rather than publishing them.
* Placeholder
f847a18 to
17fc856
Compare
… usage; update assets.json tag
17fc856 to
d68f0da
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 54 out of 54 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (5)
sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py:10511
- With
polling=False, Azure Core'sNoPolling.resource()invokes this callback with the initial 201 response. That response is anEvaluatorGenerationJob, not a terminal payload containingresult, so this path deserializes{}into an invalidEvaluatorVersion. Make the callback handle the initial response explicitly (or rejectpolling=False) and cover this mode with a test.
deserialized = _deserialize(_models.EvaluatorVersion, response.json().get("result", {}))
sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py:17020
- With
polling=False,NoPollingpasses the initial queuedDataGenerationJobresponse to this callback. Since that body has no terminalresult, the poller'sresult()becomes an invalid emptyDataGenerationJobResult. Handle the initial response explicitly or disallow this polling mode, and add coverage for it.
deserialized = _deserialize(_models.DataGenerationJobResult, response.json().get("result", {}))
sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py:17385
- The new samples use this operation with
polling=False, butNoPolling.result()invokes this callback on the initial queuedOptimizationJob. Because the initial body lacksresult, callers receive an invalid emptyOptimizationJobResult. Handle the initial response explicitly or rejectpolling=False, with a regression test.
deserialized = _deserialize(_models.OptimizationJobResult, response.json().get("result", {}))
sdk/ai/azure-ai-projects/samples/hosted_agents/rbac_util.py:88
- Checking only the deterministic assignment name does not detect an equivalent role assignment created with another UUID. Azure then rejects
createwithRoleAssignmentExists, so this “ensure” helper fails on accounts that are already configured. Query/verify the existing principal-role-scope tuple, or tolerate the conflict after confirming it matches.
sdk/ai/azure-ai-projects/samples/hosted_agents/rbac_util.py:132 - This discards the
(created, assignment_name)result, so callers cannot remove an assignment created for the temporary agent-version identity. Both toolbox samples delete that version during teardown, leaving an orphaned account-scope role assignment. Return cleanup information and delete only assignments created by the sample in itsfinallypath.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 54 out of 54 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (9)
sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py:10511
polling=FalseselectsNoPolling, whoseresult()runs this callback against the initial 201 response. That response is anEvaluatorGenerationJob, so itsresultis absent/null while queued; this returns an empty/Nonevalue instead of the advertisedEvaluatorVersion. Handle the initial response shape explicitly (and mirror the fix asynchronously), or do not exposepolling=Falsefor this LRO.
deserialized = _deserialize(_models.EvaluatorVersion, response.json().get("result", {}))
sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py:17020
- With
polling=False,NoPolling.result()invokes this callback on the initialDataGenerationJob, whose result is not available yet. Extractingresulttherefore returns an empty/NoneDataGenerationJobResult, contrary to the poller's return type. Handle the initial response shape explicitly (and mirror the fix asynchronously), or disallowpolling=Falsefor this operation.
deserialized = _deserialize(_models.DataGenerationJobResult, response.json().get("result", {}))
sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py:17385
- The new polling samples confirm that the initial 201 body is an
OptimizationJob. Whenpolling=False,NoPolling.result()passes that initial response here, so extractingresultbefore the job finishes yields an empty/NoneOptimizationJobResult. Fix the no-polling contract consistently instead of requiring callers to recover the job through an undocumentedraw_response_hook.
deserialized = _deserialize(_models.OptimizationJobResult, response.json().get("result", {}))
sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py:7086
AsyncNoPolling.result()also deserializes the initial queuedEvaluatorGenerationJob, not a terminal response. Itsresultis absent/null, sopolling=Falsereturns an empty/Nonevalue rather thanEvaluatorVersion. Apply the same initial-response contract fix as in the synchronous operation.
deserialized = _deserialize(_models.EvaluatorVersion, response.json().get("result", {}))
sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py:13968
- The initial async response is an
OptimizationJob(the new async polling sample parses it as such). Underpolling=False,AsyncNoPolling.result()sends that response here, so extractingresultreturns empty/Nonebefore completion. Fix the no-polling contract rather than forcing callers to useraw_response_hookto obtain the job ID.
deserialized = _deserialize(_models.OptimizationJobResult, response.json().get("result", {}))
sdk/ai/azure-ai-projects/samples/hosted_agents/rbac_util.py:37
- This substring match can select the wrong project when names share a prefix (for example, project
fooalso matches/projects/foobar), causing RBAC to be assigned at the wrong account scope. Match the normalized resource ID suffix exactly.
sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-emit-from-typespec/SKILL.md:37 - The prerequisite documentation explicitly supports Windows PowerShell 5.1, whose executable is
powershell.exe, notpwsh. This check therefore rejects a documented supported setup before the workflow starts. Use the Windows PowerShell command here, or implement a check that accepts either executable.
pwsh --version
sdk/ai/azure-ai-projects/samples/hosted_agents/sample_routines_with_teams_message_trigger.py:73
- The package supports Python 3.9 (
pyproject.toml:31), but evaluating this function definition on 3.9 raisesTypeErrorbecause PEP 604 unions (str | None) require Python 3.10. UseOptional[str](and importOptional) so the new sample can run on the documented minimum version.
sdk/ai/azure-ai-projects/samples/hosted_agents/rbac_util.py:88 - This only checks the deterministic assignment name generated by this helper. If the principal already has the same role and scope under an administrator-created UUID,
get()returns 404 and thiscreate()returnsRoleAssignmentExists, so an already-correct RBAC setup fails. Detect an equivalent existing assignment (or handle the duplicate-assignment response as success) before creating.
This comment has been minimized.
This comment has been minimized.
[Pilot] PR Pipeline Failure AnalysisA CI pipeline failed on this pull request. Here is an automated analysis of what went wrong and how to get the build green. What failedOne test case failed consistently across three test configurations (sdist, mindependency, and whl) on the
The failure appears in all three test run configurations, suggesting this is a test/sample code issue rather than a packaging or infrastructure problem. Recommended next steps
Raw pipeline analysis (azsdk ci analyze)
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 54 out of 54 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (6)
sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py:10511
- With
polling=False,NoPollinginvokes this callback on the initial 201 response, whose body is anEvaluatorGenerationJoband has noresultyet. This therefore deserializes{}as anEvaluatorVersionand discards the job ID, leaving callers unable to useget_generation_joborcancel_generation_jobwhile the job runs. Expose the initial job metadata through a supported poller/result API (and mirror the fix asynchronously) instead of treating the initial response as a terminal result.
deserialized = _deserialize(_models.EvaluatorVersion, response.json().get("result", {}))
sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py:7086
- With
polling=False,AsyncNoPollingresolves this callback against the initial job response, which does not containresult. The poller consequently returns an emptyEvaluatorVersionand loses the job ID needed by the public get/cancel APIs. The async LRO needs the same supported initial-job access as the sync API.
deserialized = _deserialize(_models.EvaluatorVersion, response.json().get("result", {}))
sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py:17020
- This callback strips the enclosing
DataGenerationJob, including its ID, and returns onlyDataGenerationJobResult, which has no provenance/job-ID property. Callers can no longer invoke the still-public get, cancel, or delete job methods for the job they just created; the updated samples consequently stop deleting job records. Preserve a public job ID (for example on the result, as evaluator generation does) or otherwise expose the initial/final job metadata.
deserialized = _deserialize(_models.DataGenerationJobResult, response.json().get("result", {}))
sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py:13604
- The async data-generation LRO also discards the enclosing job and returns a result type with no job ID. This makes the public async get/cancel/delete methods unusable for the newly created job without relying on raw-response internals. Preserve and expose the job identifier in the generated contract.
deserialized = _deserialize(_models.DataGenerationJobResult, response.json().get("result", {}))
sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py:17385
- With
polling=False,NoPollingcalls this deserializer on the initialOptimizationJobresponse, whereresultis absent, sopoller.result()becomes an emptyOptimizationJobResultand the job ID is lost. The new manual-polling and cancellation samples have to useraw_response_hooksolely to recover that ID. Provide a supported initial-job result/accessor so cancellation and manual polling do not depend on pipeline internals.
deserialized = _deserialize(_models.OptimizationJobResult, response.json().get("result", {}))
sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py:13968
- The async
polling=Falsepath has the same issue:AsyncNoPollingfeeds the initial job response to this callback, but noresultexists yet, producing an empty result and dropping the job ID. This is why the async manual-polling sample captures and parses a raw pipeline response. Expose initial job metadata through the public LRO API instead.
deserialized = _deserialize(_models.OptimizationJobResult, response.json().get("result", {}))
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
sdk/ai/azure-ai-projects/docs/tool-classes-removed-properties.md:43
- The count is incorrect: only the nine preview classes with non-empty entries had properties removed. The stable classes retained those properties as deprecated, as documented in
CHANGELOG.md:89-90. Update the count and summary pattern so they do not repeat the incorrect GA-removal claim.
- **Classes with removed properties:** 19
- **Common pattern:** `name`, `description`, and `tool_configs` were moved exclusively to `ToolboxTool` subclasses
| The following Tool-derived classes had properties **removed** in v2.3.0 compared to v2.2.0. These properties (`name`, `description`, `tool_configs`) now only exist on the corresponding `ToolboxTool` subclasses. | ||
|
|
||
| ## General Availability Tools | ||
|
|
||
| | Class Name | Removed Properties | | ||
| |------------|-------------------| | ||
| | `AzureAISearchTool` | `name: Optional[str]`, `description: Optional[str]`, `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `AzureFunctionTool` | `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `BingGroundingTool` | `name: Optional[str]`, `description: Optional[str]`, `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `CaptureStructuredOutputsTool` | `name: Optional[str]`, `description: Optional[str]`, `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `CodeInterpreterTool` | `name: Optional[str]`, `description: Optional[str]`, `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `FileSearchTool` | `name: Optional[str]`, `description: Optional[str]`, `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `FunctionShellToolParam` | `name: Optional[str]`, `description: Optional[str]`, `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `FunctionTool` | *(no changes)* | | ||
| | `ImageGenTool` | `name: Optional[str]`, `description: Optional[str]`, `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `LocalShellToolParam` | `name: Optional[str]`, `description: Optional[str]`, `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `MCPTool` | `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `OpenApiTool` | `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `WebSearchTool` | `name: Optional[str]`, `description: Optional[str]`, `tool_configs: Optional[dict[str, ToolConfig]]` | |
| | `MCPTool` | `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `OpenApiTool` | `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| | `WebSearchTool` | `name: Optional[str]`, `description: Optional[str]`, `tool_configs: Optional[dict[str, ToolConfig]]` | | ||
| v |
* Refactor agent name retrieval to use a fallback mechanism
- Updated multiple sample scripts to change the way the agent name is retrieved from environment variables.
- Replaced the default value assignment using `os.environ.get("FOUNDRY_AGENT_NAME", "MyAgent")` with a more concise approach using `os.environ.get("FOUNDRY_AGENT_NAME") or "MyAgent"`.
- This change ensures that if the environment variable is not set, the fallback value "MyAgent" is still used, while improving code readability.
- The affected files include various agent tools and hosted agent samples across the project.
* rever dataset generation job polling and update assistant prompt
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 53 out of 53 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (5)
sdk/ai/azure-ai-projects/docs/tool-classes-removed-properties.md:22
- Remove this stray
v; it renders as an unexplained paragraph between the two tables.
v
sdk/ai/azure-ai-projects/docs/tool-classes-removed-properties.md:3
- This is incorrect for the GA tools: the published 2.3.0 models retain these properties and mark them deprecated (for example,
AzureAISearchToolstill acceptsname,description, andtool_configs), matching CHANGELOG.md:89-90. Only the preview-tool properties were removed in 2.3.0. Rewrite the GA section and summary so users are not told that valid 2.3.0 constructor arguments disappeared.
The following Tool-derived classes had properties **removed** in v2.3.0 compared to v2.2.0. These properties (`name`, `description`, `tool_configs`) now only exist on the corresponding `ToolboxTool` subclasses.
sdk/ai/azure-ai-projects/samples/hosted_agents/hosted_agents_util.py:4
osis never referenced in this utility, so this added import will fail the package's unused-import Pylint check. Remove it.
sdk/ai/azure-ai-projects/samples/hosted_agents/github_routine_util.py:15- This new module never uses
time,urlparse,ResourceNotFoundError, orAIProjectClient, so the sample validation will report unused imports. Keep only the imports used by the two helpers.
sdk/ai/azure-ai-projects/samples/hosted_agents/sample_routines_with_github_issue_trigger.py:151 GITHUB_USERNAMEis documented as either a user or an organization, but this always sends that owner as the issue assignee. An organization cannot be assigned an issue, so automatic triggering fails for organization-owned repositories. Use a separate optional user assignee (and omitassigneeswhen absent) rather than reusing the repository owner.
No description provided.