Skip to content

Commit 11200c9

Browse files
Nathandrake229Naman Tyagi
andauthored
Scope durable task IDs by hosted session GUID (#48776)
* Scope durable task IDs by session GUID Read FOUNDRY_AGENT_SESSION_GUID in hosted configuration and use it as the private durable task namespace while preserving public conversation chain identity. Reuse active pre-rollout multi-turn tasks through a legacy-ID lookup and keep one-shot task IDs unchanged. Authored-by: GitHub Copilot CLI v1.0.81-9 Model: GPT-5.6 Sol (gpt-5.6-sol) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6d678f27-b33c-41af-b188-c852375a8762 * fix(agentserver): address session GUID review feedback Regenerate the Core API snapshot for AgentConfig.session_guid and require Core 2.2.0b1 from the Responses package so the configuration and legacy lookup APIs are always available. Authored-by: GitHub Copilot CLI v1.0.81-9 Model: GPT-5.6 Sol (gpt-5.6-sol) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6d678f27-b33c-41af-b188-c852375a8762 --------- Co-authored-by: Naman Tyagi <namantyagi@microsoft.com> Copilot-Session: 6d678f27-b33c-41af-b188-c852375a8762
1 parent aeeef3d commit 11200c9

23 files changed

Lines changed: 491 additions & 58 deletions

sdk/agentserver/azure-ai-agentserver-core/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Release History
22

3+
## 2.2.0b1 (Unreleased)
4+
5+
### Features Added
6+
7+
- Added `AgentConfig.session_guid`, populated from the platform-owned
8+
`FOUNDRY_AGENT_SESSION_GUID` environment variable for hosted session
9+
incarnation identity.
10+
311
## 2.1.0 (2026-08-24)
412

513
### Other Changes

sdk/agentserver/azure-ai-agentserver-core/api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ namespace azure.ai.agentserver.core
7979
port: int,
8080
project_endpoint: str,
8181
project_id: str,
82+
session_guid: str = "",
8283
session_id: str,
8384
sse_keepalive_interval: int,
8485
ws_ping_interval: float = 0.0
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
apiMdSha256: 018ddfb374222289f131e8655f9b4ab52192a16833c1001b42d0560731c1f14b
1+
apiMdSha256: 70c2b15bd26a79923051b648f558b9e6197363e508ee01f33d7f85eeb0298dc2
22
parserVersion: 0.3.31
3-
pythonVersion: 3.12.13
3+
pythonVersion: 3.12.10

sdk/agentserver/azure-ai-agentserver-core/azure/ai/agentserver/core/_config.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
misconfiguration is surfaced at startup rather than silently masked.
1515
"""
1616
import os
17+
import re
1718
from pathlib import Path
1819
from typing import Optional
1920

@@ -33,6 +34,7 @@
3334
_ENV_FOUNDRY_PROJECT_ENDPOINT = "FOUNDRY_PROJECT_ENDPOINT"
3435
_ENV_FOUNDRY_PROJECT_ARM_ID = "FOUNDRY_PROJECT_ARM_ID"
3536
_ENV_FOUNDRY_AGENT_SESSION_ID = "FOUNDRY_AGENT_SESSION_ID"
37+
_ENV_FOUNDRY_AGENT_SESSION_GUID = "FOUNDRY_AGENT_SESSION_GUID"
3638
_ENV_PORT = "PORT"
3739
_ENV_APPLICATIONINSIGHTS_CONNECTION_STRING = "APPLICATIONINSIGHTS_CONNECTION_STRING"
3840
_ENV_OTEL_EXPORTER_OTLP_ENDPOINT = "OTEL_EXPORTER_OTLP_ENDPOINT"
@@ -68,6 +70,8 @@ class AgentConfig: # pylint: disable=too-many-instance-attributes
6870
:param project_endpoint: Foundry project endpoint from ``FOUNDRY_PROJECT_ENDPOINT``.
6971
:param project_id: Foundry project ARM resource ID from ``FOUNDRY_PROJECT_ARM_ID``.
7072
:param session_id: Default session ID from ``FOUNDRY_AGENT_SESSION_ID``.
73+
:param session_guid: System-generated session incarnation GUID from
74+
``FOUNDRY_AGENT_SESSION_GUID``.
7175
:param port: Server port from ``PORT`` (default 8088).
7276
:param appinsights_connection_string: Application Insights connection string.
7377
:param otlp_endpoint: OTLP exporter endpoint.
@@ -92,6 +96,7 @@ def __init__(
9296
otlp_endpoint: str,
9397
sse_keepalive_interval: int,
9498
ws_ping_interval: float = 0.0,
99+
session_guid: str = "",
95100
) -> None:
96101
self.agent_name = agent_name
97102
self.agent_version = agent_version
@@ -101,6 +106,7 @@ def __init__(
101106
self.project_endpoint = project_endpoint
102107
self.project_id = project_id
103108
self.session_id = session_id
109+
self.session_guid = session_guid
104110
self.port = port
105111
self.appinsights_connection_string = appinsights_connection_string
106112
self.otlp_endpoint = otlp_endpoint
@@ -124,15 +130,23 @@ def from_env(cls) -> Self:
124130
else:
125131
agent_id = ""
126132

133+
is_hosted = bool(os.environ.get(_ENV_FOUNDRY_HOSTING_ENVIRONMENT, ""))
134+
session_guid = os.environ.get(_ENV_FOUNDRY_AGENT_SESSION_GUID, "")
135+
if is_hosted and session_guid and re.fullmatch(r"[0-9a-f]{32}", session_guid) is None:
136+
raise ValueError(
137+
"FOUNDRY_AGENT_SESSION_GUID must be a 32-character lowercase hexadecimal GUID"
138+
)
139+
127140
return cls(
128141
agent_name=agent_name,
129142
agent_version=agent_version,
130143
agent_id=agent_id,
131144
agent_guid=os.environ.get(_ENV_FOUNDRY_AGENT_ID, ""),
132-
is_hosted=bool(os.environ.get(_ENV_FOUNDRY_HOSTING_ENVIRONMENT, "")),
145+
is_hosted=is_hosted,
133146
project_endpoint=os.environ.get(_ENV_FOUNDRY_PROJECT_ENDPOINT, ""),
134147
project_id=os.environ.get(_ENV_FOUNDRY_PROJECT_ARM_ID, ""),
135148
session_id=os.environ.get(_ENV_FOUNDRY_AGENT_SESSION_ID, ""),
149+
session_guid=session_guid,
136150
port=resolve_port(None),
137151
appinsights_connection_string=os.environ.get(
138152
_ENV_APPLICATIONINSIGHTS_CONNECTION_STRING, ""),

sdk/agentserver/azure-ai-agentserver-core/azure/ai/agentserver/core/_constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ class Constants:
3030

3131
# Session identity
3232
FOUNDRY_AGENT_SESSION_ID = "FOUNDRY_AGENT_SESSION_ID"
33+
FOUNDRY_AGENT_SESSION_GUID = "FOUNDRY_AGENT_SESSION_GUID"

sdk/agentserver/azure-ai-agentserver-core/azure/ai/agentserver/core/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# Copyright (c) Microsoft Corporation. All rights reserved.
33
# ---------------------------------------------------------
44

5-
VERSION = "2.1.0"
5+
VERSION = "2.2.0b1"

sdk/agentserver/azure-ai-agentserver-core/azure/ai/agentserver/core/tasks/_decorator.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,6 +1701,16 @@ async def get_active_run(
17011701
return None
17021702
return run
17031703

1704+
async def _get(self, task_id: str) -> Any:
1705+
"""Return the persisted chain record for internal orchestration.
1706+
1707+
:param task_id: The chain task identifier.
1708+
:type task_id: str
1709+
:return: The persisted task information, or ``None`` when absent.
1710+
:rtype: Any
1711+
"""
1712+
return await self._inner._get(task_id) # noqa: SLF001 # pylint: disable=protected-access
1713+
17041714
async def delete(self, task_id: str) -> None:
17051715
"""Force-delete the chain record + any queued inputs.
17061716

sdk/agentserver/azure-ai-agentserver-core/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ authors = [
88
]
99
license = "MIT"
1010
classifiers = [
11-
"Development Status :: 5 - Production/Stable",
11+
"Development Status :: 4 - Beta",
1212
"Programming Language :: Python",
1313
"Programming Language :: Python :: 3 :: Only",
1414
"Programming Language :: Python :: 3",

sdk/agentserver/azure-ai-agentserver-core/tests/test_config.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,43 @@ def test_agent_guid_distinct_from_composite_agent_id(self, monkeypatch: pytest.M
6060
config = AgentConfig.from_env()
6161
assert config.agent_id == "weather:1"
6262
assert config.agent_guid == "guid-abc"
63+
64+
65+
class TestAgentConfigSessionGuid:
66+
"""Tests for the FOUNDRY_AGENT_SESSION_GUID resolution."""
67+
68+
def test_session_guid_from_hosted_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
69+
monkeypatch.setenv("FOUNDRY_HOSTING_ENVIRONMENT", "production")
70+
monkeypatch.setenv("FOUNDRY_AGENT_SESSION_GUID", "a" * 32)
71+
72+
config = AgentConfig.from_env()
73+
74+
assert config.session_guid == "a" * 32
75+
76+
def test_session_guid_empty_when_absent(self, monkeypatch: pytest.MonkeyPatch) -> None:
77+
monkeypatch.delenv("FOUNDRY_AGENT_SESSION_GUID", raising=False)
78+
79+
config = AgentConfig.from_env()
80+
81+
assert config.session_guid == ""
82+
83+
@pytest.mark.parametrize("value", ["A" * 32, "a" * 31, "g" * 32, "not-a-guid"])
84+
def test_invalid_hosted_session_guid_raises(
85+
self, monkeypatch: pytest.MonkeyPatch, value: str
86+
) -> None:
87+
monkeypatch.setenv("FOUNDRY_HOSTING_ENVIRONMENT", "production")
88+
monkeypatch.setenv("FOUNDRY_AGENT_SESSION_GUID", value)
89+
90+
with pytest.raises(ValueError, match="FOUNDRY_AGENT_SESSION_GUID"):
91+
AgentConfig.from_env()
92+
93+
def test_non_hosted_invalid_session_guid_is_not_trusted(
94+
self, monkeypatch: pytest.MonkeyPatch
95+
) -> None:
96+
monkeypatch.delenv("FOUNDRY_HOSTING_ENVIRONMENT", raising=False)
97+
monkeypatch.setenv("FOUNDRY_AGENT_SESSION_GUID", "local-value")
98+
99+
config = AgentConfig.from_env()
100+
101+
assert config.is_hosted is False
102+
assert config.session_guid == "local-value"

sdk/agentserver/azure-ai-agentserver-responses/CHANGELOG.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@
22

33
## 2.2.0b2 (Unreleased)
44

5-
### Features Added
6-
7-
### Breaking Changes
8-
95
### Bugs Fixed
106

7+
- Scoped durable multi-turn task IDs with `FOUNDRY_AGENT_SESSION_GUID` when
8+
available, preventing recreated same-name sessions from colliding with task
9+
tombstones. Existing pre-rollout active chains remain resumable through a
10+
legacy-ID lookup.
11+
1112
### Other Changes
1213

14+
- Raised the minimum `azure-ai-agentserver-core` dependency to `>=2.2.0b1`,
15+
which provides the session GUID configuration and legacy task lookup used by
16+
resilient Responses.
17+
1318
## 2.2.0b1 (2026-08-27)
1419

1520
### Breaking Changes

0 commit comments

Comments
 (0)