Python: [BREAKING] Fix #3613 chat/agent message typing alignment (#3920)

* Fix #3613 message typing across chat and agents

* Address #3613 review feedback and sample input style

* refactor: use shared AgentRunMessages aliases (#3613)

* refactor: rename agent run input aliases for #3613

* samples: inline image content in run calls

* core: export AgentRunInputs from package init

* core: use explicit init re-exports without __all__

* updated logging and inits

* Fix core mypy export and samples XML note

* Remove AgentRunInputsOrNone and dedupe loggers

* Remove prepare_messages helper

* fix integration tests
This commit is contained in:
Eduard van Valkenburg
2026-02-16 16:27:25 +01:00
committed by GitHub
Unverified
parent 503eb10fdd
commit dc9439a75a
87 changed files with 422 additions and 578 deletions
@@ -8,14 +8,16 @@ with durable agents via gRPC.
from __future__ import annotations
from agent_framework import AgentResponse, get_logger
import logging
from agent_framework import AgentResponse
from durabletask.client import TaskHubGrpcClient
from ._constants import DEFAULT_MAX_POLL_RETRIES, DEFAULT_POLL_INTERVAL_SECONDS
from ._executors import ClientAgentExecutor
from ._shim import DurableAgentProvider, DurableAIAgent
logger = get_logger("agent_framework.durabletask.client")
logger = logging.getLogger("agent_framework.durabletask")
class DurableAIAgentClient(DurableAgentProvider[AgentResponse]):
@@ -30,6 +30,7 @@ All classes support bidirectional conversion between:
from __future__ import annotations
import json
import logging
from collections.abc import MutableMapping
from datetime import datetime, timezone
from enum import Enum
@@ -40,14 +41,13 @@ from agent_framework import (
Content,
Message,
UsageDetails,
get_logger,
)
from dateutil import parser as date_parser
from ._constants import ContentTypes, DurableStateFields
from ._models import RunRequest, serialize_response_format
logger = get_logger("agent_framework.durabletask.durable_agent_state")
logger = logging.getLogger("agent_framework.durabletask")
class DurableAgentStateEntryJsonType(str, Enum):
@@ -5,6 +5,7 @@
from __future__ import annotations
import inspect
import logging
from datetime import datetime, timezone
from typing import Any, cast
@@ -15,7 +16,6 @@ from agent_framework import (
Message,
ResponseStream,
SupportsAgentRun,
get_logger,
)
from durabletask.entities import DurableEntity
@@ -28,7 +28,7 @@ from ._durable_agent_state import (
)
from ._models import RunRequest
logger = get_logger("agent_framework.durabletask.entities")
logger = logging.getLogger("agent_framework.durabletask")
class AgentEntityStateProviderMixin:
@@ -10,13 +10,14 @@ and are injected into the shim.
from __future__ import annotations
import logging
import time
import uuid
from abc import ABC, abstractmethod
from datetime import datetime, timezone
from typing import Any, Generic, TypeVar
from agent_framework import AgentResponse, AgentSession, Content, Message, get_logger
from agent_framework import AgentResponse, AgentSession, Content, Message
from durabletask.client import TaskHubGrpcClient
from durabletask.entities import EntityInstanceId
from durabletask.task import CompletableTask, CompositeTask, OrchestrationContext, Task
@@ -27,7 +28,7 @@ from ._durable_agent_state import DurableAgentState
from ._models import AgentSessionId, DurableAgentSession, RunRequest
from ._response_utils import ensure_response_format, load_agent_response
logger = get_logger("agent_framework.durabletask.executors")
logger = logging.getLogger("agent_framework.durabletask")
# TypeVar for the task type returned by executors
TaskT = TypeVar("TaskT")
@@ -8,13 +8,14 @@ orchestration functions to interact with durable agents.
from __future__ import annotations
from agent_framework import get_logger
import logging
from durabletask.task import OrchestrationContext
from ._executors import DurableAgentTask, OrchestrationAgentExecutor
from ._shim import DurableAgentProvider, DurableAIAgent
logger = get_logger("agent_framework.durabletask.orchestration_context")
logger = logging.getLogger("agent_framework.durabletask")
class DurableAIAgentOrchestrationContext(DurableAgentProvider[DurableAgentTask]):
@@ -2,12 +2,13 @@
"""Shared utilities for handling AgentResponse parsing and validation."""
import logging
from typing import Any
from agent_framework import AgentResponse, get_logger
from agent_framework import AgentResponse
from pydantic import BaseModel
logger = get_logger("agent_framework.durabletask.response_utils")
logger = logging.getLogger("agent_framework.durabletask")
def load_agent_response(agent_response: AgentResponse | dict[str, Any] | None) -> AgentResponse:
@@ -12,7 +12,8 @@ from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any, Generic, Literal, TypeVar
from agent_framework import AgentSession, Message, SupportsAgentRun
from agent_framework import AgentSession, SupportsAgentRun, normalize_messages
from agent_framework._types import AgentRunInputs
from ._executors import DurableAgentExecutor
from ._models import DurableAgentSession
@@ -86,7 +87,7 @@ class DurableAIAgent(SupportsAgentRun, Generic[TaskT]):
def run( # type: ignore[override]
self,
messages: str | Message | list[str] | list[Message] | None = None,
messages: AgentRunInputs | None = None,
*,
stream: Literal[False] = False,
session: AgentSession | None = None,
@@ -143,7 +144,7 @@ class DurableAIAgent(SupportsAgentRun, Generic[TaskT]):
"""
return self._executor.get_new_session(self.name, **kwargs)
def _normalize_messages(self, messages: str | Message | list[str] | list[Message] | None) -> str:
def _normalize_messages(self, messages: AgentRunInputs | None) -> str:
"""Convert supported message inputs to a single string.
Args:
@@ -151,19 +152,18 @@ class DurableAIAgent(SupportsAgentRun, Generic[TaskT]):
Returns:
A single string representation of the messages
Raises:
ValueError: If normalized messages contain non-text content only.
"""
if messages is None:
normalized_messages = normalize_messages(messages)
if not normalized_messages:
return ""
if isinstance(messages, str):
return messages
if isinstance(messages, Message):
return messages.text or ""
if isinstance(messages, list):
if not messages:
return ""
first_item = messages[0]
if isinstance(first_item, str):
return "\n".join(messages) # type: ignore[arg-type]
# List of Message
return "\n".join([msg.text or "" for msg in messages]) # type: ignore[union-attr]
return ""
message_texts: list[str] = []
for message in normalized_messages:
if not message.text:
raise ValueError("DurableAIAgent only supports text message inputs.")
message_texts.append(message.text)
return "\n".join(message_texts)
@@ -9,15 +9,16 @@ and enables registration of agents as durable entities.
from __future__ import annotations
import asyncio
import logging
from typing import Any
from agent_framework import SupportsAgentRun, get_logger
from agent_framework import SupportsAgentRun
from durabletask.worker import TaskHubGrpcWorker
from ._callbacks import AgentResponseCallbackProtocol
from ._entities import AgentEntity, DurableTaskEntityStateProvider
logger = get_logger("agent_framework.durabletask.worker")
logger = logging.getLogger("agent_framework.durabletask")
class DurableAIAgentWorker: