diff --git a/sdk/ai/azure-ai-projects/PostEmitter.ps1 b/sdk/ai/azure-ai-projects/PostEmitter.ps1 new file mode 100644 index 000000000000..cac7cf0aa873 --- /dev/null +++ b/sdk/ai/azure-ai-projects/PostEmitter.ps1 @@ -0,0 +1,193 @@ +# +# To emit from TypeSpec, run this in the current folder: +# +# tsp-client update --debug ==> to use the commit mentioned in the local tsp-location.yaml to generate +# tsp-client update --debug --save-inputs" ==> To save the local folder TempTypeSpecFiles +# tsp-client update --debug --local-spec-repo " ==> to use your local TypeSpec folder. Path is like: +# D:\src\azure-rest-api-specs\specification\ai-foundry\data-plane\Foundry\src\sdk-python-js-azure-ai-projects +# +# Then run this script to "fix" the emitted code: +# powershell -ExecutionPolicy Bypass -File PostEmitter.ps1 +# + +# Revert emitted pyprojects.toml, since it overrides the following changes: +# - We added "Programming Language :: Python :: 3.14". The emitter removes it. +# - The emitter uses lower case "i" in "Ai". I want to keep it upper case in the description field: "Microsoft Corporation Azure AI Projects Client Library for Python". +# - We want a vanity link for the "repository" value, deep linking to the SDK folder (not root of repo): https://aka.ms/azsdk/azure-ai-projects-v2/python/code +git restore pyproject.toml + + +# Edit both _operations.py files to fix missing Foundry-Features HTTP request header in continued list paging calls. Add: +# headers=_headers +# to the end of each of these lines in the BetaXxxOperations classes (do not do this in GA operations classes!) +# "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params +# In emitted code, these first 7 of those lines are associated with GA operations, so start the replacement +# from the 8th occurrence onward. +$gaCount = 7 +$old = [char]34 + 'GET' + [char]34 + ', urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params' +$new = $old + ', headers=_headers' +foreach ($f in 'azure\ai\projects\aio\operations\_operations.py', 'azure\ai\projects\operations\_operations.py') { + $c = Get-Content $f -Raw + $parts = $c -split [regex]::Escape($old) + $r = $parts[0] + for ($i = 1; $i -lt $parts.Length; $i++) { + if ($i -le $gaCount) { + $r += $old + $parts[$i] + } else { + $r += $new + $parts[$i] + } + } + Set-Content $f $r -NoNewline +} + +# Force streaming in get_session_log_stream for both sync and async operations. +$files = 'azure\ai\projects\operations\_operations.py', 'azure\ai\projects\aio\operations\_operations.py' +foreach ($f in $files) { + $lines = Get-Content $f + $inFunc = $false + for ($i = 0; $i -lt $lines.Length; $i++) { + if ($lines[$i] -match '^\s*(async\s+)?def\s+get_session_log_stream\(') { + $inFunc = $true + continue + } + if ($inFunc -and $lines[$i] -match '^\s*(async\s+)?def\s+\w+\(') { + $inFunc = $false + } + if ($inFunc -and $lines[$i] -match 'kwargs\.pop\(.+stream.+False\)') { + $indent = ([regex]::Match($lines[$i], '^\s*')).Value + $lines[$i] = $indent + '_stream = True' + } + } + Set-Content $f $lines +} + +# Fix Sphinx issue in class ToolChoiceAllowed, in "tools" property doc string. The "Required" cannot come at the end of the code-block. +# move it to the end of the text before the code block, and make sure there are no periods after "]". +# .. code-block:: json +# +# [ +# { "type": "function", "name": "get_weather" }, +# { "type": "mcp", "server_label": "deepwiki" }, +# { "type": "image_generation" } +# ]. Required. +(Get-Content azure\ai\projects\models\_models.py) -replace 'Responses API, the list of tool definitions might look like:', 'Responses API, the list of tool definitions might look like the following. Required.' | Set-Content azure\ai\projects\models\_models.py +(Get-Content azure\ai\projects\models\_models.py) -replace 'list of tool definitions might look like:', 'list of tool definitions might look like the following. Required.' | Set-Content azure\ai\projects\models\_models.py +(Get-Content azure\ai\projects\models\_models.py) -replace ' \]\. Required\.', ' ]' | Set-Content azure\ai\projects\models\_models.py + +# Fix Sphinx docutils warnings in class SessionLogEvent: the generated docstring wraps two long +# ``data:`` JSON lines mid-string inside a ``.. code-block::`` section. The wrapped continuation +# lines have wrong indentation (4 spaces instead of 7), causing "unexpected unindent" warnings. +# Join each broken pair back into one line. +$f = 'azure\ai\projects\models\_models.py' +$c = Get-Content $f -Raw +$c = $c -replace '(Starting server)\r?\n[ \t]+(on port 18080)', '$1 $2' +$c = $c -replace '(Successfully)\r?\n[ \t]+(connected to container\"})\.?', '$1 $2' +Set-Content $f $c -NoNewline +$lines = Get-Content $f +$out = @() +foreach ($line in $lines) { + if ($line -match '^\s*on port 18080' -and $line -notmatch 'data:') { continue } + if ($line -match '^\s*connected to container' -and $line -notmatch 'data:') { continue } + if ($line -match '^\s*data: .*2026-03-10T09:33:17.121Z') { + $out += (' ' + $line.TrimStart()) + continue + } + if ($line -match '^\s*data: .*2026-03-10T09:34:52.714Z') { + $out += (' ' + $line.TrimStart()) + continue + } + $out += $line +} +Set-Content $f $out + +# Fix Sphinx docutils warnings in get_session_log_stream docstrings (sync + async). +# The emitter wraps bullet/code-block lines with insufficient indentation. +$files = 'azure\ai\projects\operations\_operations.py', 'azure\ai\projects\aio\operations\_operations.py' +foreach ($f in $files) { + $c = Get-Content $f -Raw + $c = $c -replace 'schema\r?\n\s+is not contractual and may include additional keys or change format\r?\n\s+over time [^\r\n]*clients should treat it as an opaque string\)', 'schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string)' + $c = $c -replace '(message\":\"Starting)\r?\n\s+(FoundryCBAgent server on port 8088\"})', '$1 $2' + $c = $c -replace '(message\":\"INFO: Application)\r?\n\s+(startup complete\.\"})', '$1 $2' + $c = $c -replace '(message\":\"Successfully)\r?\n\s+(connected to container\"})', '$1 $2' + $c = $c -replace '(message\":\"No logs since)\r?\n\s+(last 60 seconds\"})', '$1 $2' + Set-Content $f $c -NoNewline +} + +# A block of code in the implementation of "list_memories", in both sync +# and async _operations.py files, needs to be moved up. It's emitted in the wrong place, +# in the inline function named "prepare_request". Instead it should be moved up into the +# main body of the "list_memories" method, right after the line `error_map.update(kwargs.pop("error_map", {}) or {})`. +# If you don't do this, the PR pipeline will show failures in Pyright (`error: "body" is unbound (reportUnboundVariable)`) +# and some tests will fail. This is the block of code that needs to move up: +# if body is _Unset: +# if scope is _Unset: +# raise TypeError("missing required argument: scope") +# body = {"scope": scope} +# body = {k: v for k, v in body.items() if v is not None} +# The block inside prepare_request has 12-space indentation; after moving to the main function body it needs 8-space indentation. +# Strategy: Find the last list_memories method, then do a targeted string replacement that moves the block right after error_map.update. +$oldPattern = @" + error_map.update(kwargs.pop("error_map", {}) or {}) + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + def prepare_request(_continuation_token=None): + if body is _Unset: + if scope is _Unset: + raise TypeError("missing required argument: scope") + body = {"scope": scope} + body = {k: v for k, v in body.items() if v is not None} + + _request = build_beta_memory_stores_list_memories_request( +"@ +$newPattern = @" + error_map.update(kwargs.pop("error_map", {}) or {}) + if body is _Unset: + if scope is _Unset: + raise TypeError("missing required argument: scope") + body = {"scope": scope} + body = {k: v for k, v in body.items() if v is not None} + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + def prepare_request(_continuation_token=None): + _request = build_beta_memory_stores_list_memories_request( +"@ +$files = 'azure\ai\projects\operations\_operations.py', 'azure\ai\projects\aio\operations\_operations.py' +foreach ($f in $files) { + $c = Get-Content $f -Raw + # Find all occurrences of "def list_memories(" and get the index of the last one + $methodMatches = [regex]::Matches($c, 'def list_memories\(') + if ($methodMatches.Count -eq 0) { continue } + $lastMethodStart = $methodMatches[$methodMatches.Count - 1].Index + + # Find the pattern to replace - first occurrence after the last list_memories method + $patternEscaped = [regex]::Escape($oldPattern) + $patternMatches = [regex]::Matches($c, $patternEscaped) + $matchToReplace = $null + foreach ($m in $patternMatches) { + if ($m.Index -gt $lastMethodStart) { + $matchToReplace = $m + break + } + } + if ($matchToReplace -eq $null) { continue } + + # Replace only that specific occurrence + $c = $c.Substring(0, $matchToReplace.Index) + $newPattern + $c.Substring($matchToReplace.Index + $matchToReplace.Length) + + Set-Content $f $c -NoNewline +} + + +# Finishing by running 'black' tool to format code. +pip install black +black --config ../../../eng/black-pyproject.toml . diff --git a/sdk/ai/azure-ai-projects/api.md b/sdk/ai/azure-ai-projects/api.md index 657edf783e06..aa20e54a46e6 100644 --- a/sdk/ai/azure-ai-projects/api.md +++ b/sdk/ai/azure-ai-projects/api.md @@ -6954,14 +6954,14 @@ namespace azure.ai.projects.models class azure.ai.projects.models.OptimizationInlineDatasetInput(OptimizationDatasetInput, discriminator='inline'): - items_property: list[OptimizationDatasetItem] + dataset_items: list[OptimizationDatasetItem] type: Literal[OptimizationDatasetInputType.INLINE] @overload def __init__( self, *, - items_property: list[OptimizationDatasetItem] + dataset_items: list[OptimizationDatasetItem] ) -> None: ... @overload diff --git a/sdk/ai/azure-ai-projects/api.metadata.yml b/sdk/ai/azure-ai-projects/api.metadata.yml index f930bb0f724f..881bafc80613 100644 --- a/sdk/ai/azure-ai-projects/api.metadata.yml +++ b/sdk/ai/azure-ai-projects/api.metadata.yml @@ -1,3 +1,3 @@ -apiMdSha256: 21533487ff2217a30e5e9e61194466340ea4be034aef29cc66784996eaa298d0 +apiMdSha256: f4c05c4124d4d6f1d59ec55aefc17f8184427317294f3a526d8d98d6133c35d8 parserVersion: 0.3.28 pythonVersion: 3.14.3 diff --git a/sdk/ai/azure-ai-projects/apiview-properties.json b/sdk/ai/azure-ai-projects/apiview-properties.json index 37f1180762a5..56060921e407 100644 --- a/sdk/ai/azure-ai-projects/apiview-properties.json +++ b/sdk/ai/azure-ai-projects/apiview-properties.json @@ -481,5 +481,5 @@ "azure.ai.projects.operations.IndexesOperations.create_or_update": "Azure.AI.Projects.Indexes.createOrUpdateVersion", "azure.ai.projects.aio.operations.IndexesOperations.create_or_update": "Azure.AI.Projects.Indexes.createOrUpdateVersion" }, - "CrossLanguageVersion": "0ee459332041" + "CrossLanguageVersion": "54953c829a31" } \ No newline at end of file diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py index e278f6761204..6d72581d3585 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py @@ -9013,14 +9013,11 @@ def list_memories( 304: ResourceNotModifiedError, } error_map.update(kwargs.pop("error_map", {}) or {}) - - # BUG? These lines were inside the prepare_request() method. Moved here instead. if body is _Unset: if scope is _Unset: raise TypeError("missing required argument: scope") body = {"scope": scope} body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" _content = None if isinstance(body, (IOBase, bytes)): @@ -9029,12 +9026,6 @@ def list_memories( _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore def prepare_request(_continuation_token=None): - # if body is _Unset: - # if scope is _Unset: - # raise TypeError("missing required argument: scope") - # body = {"scope": scope} - # body = {k: v for k, v in body.items() if v is not None} - _request = build_beta_memory_stores_list_memories_request( name=name, kind=kind, diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py index f5f7d8f14d09..e6fb3a3e2bbf 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py @@ -10824,15 +10824,15 @@ class OptimizationInlineDatasetInput(OptimizationDatasetInput, discriminator="in :ivar type: Dataset input type discriminator. Required. Inline dataset — items are provided directly in the request body. :vartype type: str or ~azure.ai.projects.models.INLINE - :ivar items_property: Dataset items. Required. - :vartype items_property: list[~azure.ai.projects.models.OptimizationDatasetItem] + :ivar dataset_items: Dataset items. Required. + :vartype dataset_items: list[~azure.ai.projects.models.OptimizationDatasetItem] """ type: Literal[OptimizationDatasetInputType.INLINE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Dataset input type discriminator. Required. Inline dataset — items are provided directly in the request body.""" - items_property: list["_models.OptimizationDatasetItem"] = rest_field( - name="items", visibility=["read", "create", "update", "delete", "query"], original_tsp_name="items" + dataset_items: list["_models.OptimizationDatasetItem"] = rest_field( + name="items", visibility=["read", "create", "update", "delete", "query"] ) """Dataset items. Required.""" @@ -10840,7 +10840,7 @@ class OptimizationInlineDatasetInput(OptimizationDatasetInput, discriminator="in def __init__( self, *, - items_property: list["_models.OptimizationDatasetItem"], + dataset_items: list["_models.OptimizationDatasetItem"], ) -> None: ... @overload diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py index 09319efc0d67..2ca2deb79964 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py @@ -12436,14 +12436,11 @@ def list_memories( 304: ResourceNotModifiedError, } error_map.update(kwargs.pop("error_map", {}) or {}) - - # BUG? These lines were inside the prepare_request() method. Moved here instead. if body is _Unset: if scope is _Unset: raise TypeError("missing required argument: scope") body = {"scope": scope} body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" _content = None if isinstance(body, (IOBase, bytes)): @@ -12452,12 +12449,6 @@ def list_memories( _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore def prepare_request(_continuation_token=None): - # if body is _Unset: - # if scope is _Unset: - # raise TypeError("missing required argument: scope") - # body = {"scope": scope} - # body = {k: v for k, v in body.items() if v is not None} - _request = build_beta_memory_stores_list_memories_request( name=name, kind=kind, diff --git a/sdk/ai/azure-ai-projects/post-emitter-fixes.cmd b/sdk/ai/azure-ai-projects/post-emitter-fixes.cmd deleted file mode 100644 index 1001de9c2f8e..000000000000 --- a/sdk/ai/azure-ai-projects/post-emitter-fixes.cmd +++ /dev/null @@ -1,77 +0,0 @@ -REM -REM To emit from TypeSpec, run this in the current folder: -REM -REM tsp-client update --debug --local-spec-repo e:\src\azure-rest-api-specs\specification\ai-foundry\data-plane\Foundry -REM -REM (replace `e:\src\...` with the local folder containing up to date TypeSpec) -REM -REM Then run this script to "fix" the emitted code. -REM - -REM Revert emitted pyprojects.toml, since it overrides the following changes: -REM - We added "Programming Language :: Python :: 3.14". The emitter removes it. -REM - The emitter uses lower case "i" in "Ai". I want to keep it upper case in the description field: "Microsoft Corporation Azure AI Projects Client Library for Python". -REM - We want a vanity link for the "repository" value, deep linking to the SDK folder (not root of repo): https://aka.ms/azsdk/azure-ai-projects-v2/python/code -git restore pyproject.toml - -REM Rename `"items_property": items`, to `"items": items` in search_memories and begin_update_memories methods. "items" is specified in TypeSpec, but Python emitter does not allow it. -powershell -Command "(Get-Content azure\ai\projects\aio\operations\_operations.py) -replace '\"items_property\": items', '\"items\": items' | Set-Content azure\ai\projects\aio\operations\_operations.py" -powershell -Command "(Get-Content azure\ai\projects\operations\_operations.py) -replace '\"items_property\": items', '\"items\": items' | Set-Content azure\ai\projects\operations\_operations.py" - -REM Rename WEB_SEARCH_PREVIEW2025_03_11 enum member to WEB_SEARCH_PREVIEW_2025_03_11, to match actual string value -powershell -Command "(Get-Content azure\ai\projects\models\_enums.py) -replace 'WEB_SEARCH_PREVIEW2025_03_11', 'WEB_SEARCH_PREVIEW_2025_03_11' | Set-Content azure\ai\projects\models\_enums.py" -powershell -Command "(Get-Content azure\ai\projects\models\_models.py) -replace 'WEB_SEARCH_PREVIEW2025_03_11', 'WEB_SEARCH_PREVIEW_2025_03_11' | Set-Content azure\ai\projects\models\_models.py" - -REM Rename DEFAULT2024_11_15 to DEFAULT_2024_11_15 -powershell -Command "(Get-Content azure\ai\projects\models\_enums.py) -replace 'DEFAULT2024_11_15', 'DEFAULT_2024_11_15' | Set-Content azure\ai\projects\models\_enums.py" - -REM Rename `A2_A` to `A2A` in enum class AgentEndpointProtocol and ToolType -powershell -Command "(Get-Content azure\ai\projects\models\_enums.py) -replace 'A2_A', 'A2A' | Set-Content azure\ai\projects\models\_enums.py" -powershell -Command "(Get-Content azure\ai\projects\models\_models.py) -replace 'A2_A', 'A2A' | Set-Content azure\ai\projects\models\_models.py" - -REM Rename MEMORY1_GB/MEMORY4_GB/MEMORY16_GB/MEMORY64_GB to MEMORY_1GB/MEMORY_4GB/MEMORY_16GB/MEMORY_64GB in enum class ContainerMemoryLimit -REM For some reason these TypeSpec decorators stopped working. Need to understand why: @@clientName(OpenAI.ContainerMemoryLimit.`1g`, "MEMORY_1GB", "python"); -powershell -Command "(Get-Content azure\ai\projects\models\_enums.py) -replace 'MEMORY1_GB', 'MEMORY_1GB' | Set-Content azure\ai\projects\models\_enums.py" -powershell -Command "(Get-Content azure\ai\projects\models\_enums.py) -replace 'MEMORY4_GB', 'MEMORY_4GB' | Set-Content azure\ai\projects\models\_enums.py" -powershell -Command "(Get-Content azure\ai\projects\models\_enums.py) -replace 'MEMORY16_GB', 'MEMORY_16GB' | Set-Content azure\ai\projects\models\_enums.py" -powershell -Command "(Get-Content azure\ai\projects\models\_enums.py) -replace 'MEMORY64_GB', 'MEMORY_64GB' | Set-Content azure\ai\projects\models\_enums.py" - -REM Edit both _operations.py files to fix missing Foundry-Features HTTP request header in continued list paging calls. Add: -REM headers=_headers -REM to the end of each of these lines in the BetaXxxOperations classes (do not do this in GA operations classes!) -REM "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params -REM In emitted code, these first 7 of those lines are associated with GA operations, so start the replacement -REM from the 8th occurrence onward. -powershell -Command "$gaCount=7; $old=[char]34+'GET'+[char]34+', urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params'; $new=$old+', headers=_headers'; foreach ($f in 'azure\ai\projects\aio\operations\_operations.py','azure\ai\projects\operations\_operations.py') { $c=Get-Content $f -Raw; $parts=$c -split [regex]::Escape($old); $r=$parts[0]; for ($i=1; $i -lt $parts.Length; $i++) { if ($i -le $gaCount) { $r+=$old+$parts[$i] } else { $r+=$new+$parts[$i] } }; Set-Content $f $r -NoNewline }" - -REM Force streaming in get_session_log_stream for both sync and async operations. -powershell -Command "$files='azure\ai\projects\operations\_operations.py','azure\ai\projects\aio\operations\_operations.py'; foreach ($f in $files) { $lines=Get-Content $f; $inFunc=$false; for ($i=0; $i -lt $lines.Length; $i++) { if ($lines[$i] -match '^\s*(async\s+)?def\s+get_session_log_stream\(') { $inFunc=$true; continue }; if ($inFunc -and $lines[$i] -match '^\s*(async\s+)?def\s+\w+\(') { $inFunc=$false }; if ($inFunc -and $lines[$i] -match 'kwargs\.pop\(.+stream.+False\)') { $indent=([regex]::Match($lines[$i], '^\s*')).Value; $lines[$i]=$indent + '_stream = True' } }; Set-Content $f $lines }" - -REM Fix Sphinx issue in class ToolChoiceAllowed, in "tools" property doc string. The "Required" cannot come at the end of the code-block. -REM move it to the end of the text before the code block, and make sure there are no periods after "]". -REM .. code-block:: json -REM -REM [ -REM { "type": "function", "name": "get_weather" }, -REM { "type": "mcp", "server_label": "deepwiki" }, -REM { "type": "image_generation" } -REM ]. Required. -powershell -Command "(Get-Content azure\ai\projects\models\_models.py) -replace 'Responses API, the list of tool definitions might look like:', 'Responses API, the list of tool definitions might look like the following. Required.' | Set-Content azure\ai\projects\models\_models.py" -powershell -Command "(Get-Content azure\ai\projects\models\_models.py) -replace 'list of tool definitions might look like:', 'list of tool definitions might look like the following. Required.' | Set-Content azure\ai\projects\models\_models.py" -powershell -Command "(Get-Content azure\ai\projects\models\_models.py) -replace ' \]\. Required\.', ' ]' | Set-Content azure\ai\projects\models\_models.py" - -REM Fix Sphinx docutils warnings in class SessionLogEvent: the generated docstring wraps two long -REM ``data:`` JSON lines mid-string inside a ``.. code-block::`` section. The wrapped continuation -REM lines have wrong indentation (4 spaces instead of 7), causing "unexpected unindent" warnings. -REM Join each broken pair back into one line. -powershell -Command "$f='azure\ai\projects\models\_models.py'; $c=Get-Content $f -Raw; $c=$c -replace '(Starting server)\r?\n[ \t]+(on port 18080)', '$1 $2'; $c=$c -replace '(Successfully)\r?\n[ \t]+(connected to container\"})\.?', '$1 $2'; Set-Content $f $c -NoNewline; $lines=Get-Content $f; $out=@(); foreach ($line in $lines) { if ($line -match '^\s*on port 18080' -and $line -notmatch 'data:') { continue }; if ($line -match '^\s*connected to container' -and $line -notmatch 'data:') { continue }; if ($line -match '^\s*data: .*2026-03-10T09:33:17.121Z') { $out += (' ' + $line.TrimStart()); continue }; if ($line -match '^\s*data: .*2026-03-10T09:34:52.714Z') { $out += (' ' + $line.TrimStart()); continue }; $out += $line }; Set-Content $f $out" - -REM Fix Sphinx docutils warnings in get_session_log_stream docstrings (sync + async). -REM The emitter wraps bullet/code-block lines with insufficient indentation. -powershell -Command "$files='azure\ai\projects\operations\_operations.py','azure\ai\projects\aio\operations\_operations.py'; foreach ($f in $files) { $c=Get-Content $f -Raw; $c=$c -replace 'schema\r?\n\s+is not contractual and may include additional keys or change format\r?\n\s+over time [^\r\n]*clients should treat it as an opaque string\)', 'schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string)'; $c=$c -replace '(message\":\"Starting)\r?\n\s+(FoundryCBAgent server on port 8088\"})', '$1 $2'; $c=$c -replace '(message\":\"INFO: Application)\r?\n\s+(startup complete\.\"})', '$1 $2'; $c=$c -replace '(message\":\"Successfully)\r?\n\s+(connected to container\"})', '$1 $2'; $c=$c -replace '(message\":\"No logs since)\r?\n\s+(last 60 seconds\"})', '$1 $2'; Set-Content $f $c -NoNewline }" - -REM Finishing by running 'black' tool to format code. -pip install black -black --config ../../../eng/black-pyproject.toml . - -