Skip to content

Commit a555f72

Browse files
[agentserver] core: make TaskRun awaitable (return .result())
Adds TaskRun.__await__ so callers can write: run = await my_task.start(task_id=..., input=...) ... result = await run as shorthand for the existing: result = await run.result() This is the natural Pythonic shape for handle-style awaitables and removes a pyright complaint when users naively do 'await run' on a TaskRun handle. Both APIs continue to work: .__await__ delegates to .result(). Test: tests/durable/test_lifecycle.py::test_task_run_is_awaitable verifies both 'await run' and 'await run.result()' return equivalent TaskResults. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 17af169 commit a555f72

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

sdk/agentserver/azure-ai-agentserver-core/azure/ai/agentserver/core/durable/_run.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,23 @@ async def __anext__(self) -> Any:
243243
if self._stream_handler is None:
244244
raise StopAsyncIteration
245245
return await self._stream_handler.get()
246+
247+
def __await__(self) -> Any:
248+
"""Awaiting a :class:`TaskRun` returns its :meth:`result`.
249+
250+
Lets callers write ``result = await run`` as shorthand for
251+
``result = await run.result()``. Useful when you already have
252+
a ``TaskRun`` handle (e.g. from :meth:`Task.start` or
253+
:meth:`Task.get_active_run`) and just want the terminal
254+
outcome.
255+
256+
Usage::
257+
258+
run = await my_task.start(task_id="t1", input=...)
259+
...
260+
result = await run
261+
262+
:return: The :class:`TaskResult` for this run.
263+
:rtype: TaskResult[Output]
264+
"""
265+
return self.result().__await__()

sdk/agentserver/azure-ai-agentserver-core/tests/durable/test_lifecycle.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,28 @@ async def my_task(ctx: TaskContext[str]) -> str:
290290
finally:
291291
await self._teardown_manager(manager, mgr_mod)
292292

293+
@pytest.mark.asyncio
294+
async def test_task_run_is_awaitable(self, tmp_path) -> None:
295+
"""``await task_run`` returns the same TaskResult as ``await task_run.result()``."""
296+
297+
@task(title="awaitable")
298+
async def my_task(ctx: TaskContext[str]) -> str:
299+
return f"echo: {ctx.input}"
300+
301+
manager, mgr_mod = await self._setup_manager(tmp_path)
302+
try:
303+
# Direct-await the TaskRun handle.
304+
handle = await my_task.start(task_id="awaitable-1", input="hello")
305+
result = await handle # ← exercising __await__
306+
assert result.output == "echo: hello"
307+
308+
# And confirm the explicit .result() path still works identically.
309+
handle2 = await my_task.start(task_id="awaitable-2", input="world")
310+
result_via_method = await handle2.result()
311+
assert result_via_method.output == "echo: world"
312+
finally:
313+
await self._teardown_manager(manager, mgr_mod)
314+
293315
@pytest.mark.asyncio
294316
async def test_stale_timeout_kwarg_removed_spec_016(self, tmp_path) -> None:
295317
"""Spec 016 FR-001 / US1: stale_timeout removed from developer surface.

0 commit comments

Comments
 (0)