Skip to content

Commit 9e97938

Browse files
latency improvements
1 parent 0e152a0 commit 9e97938

3 files changed

Lines changed: 23 additions & 19 deletions

File tree

python/packages/core/agent_framework/_tools.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ class WeatherArgs(BaseModel):
573573
"""
574574

575575
INJECTABLE: ClassVar[set[str]] = {"func"}
576-
DEFAULT_EXCLUDE: ClassVar[set[str]] = {"input_model", "_invocation_duration_histogram"}
576+
DEFAULT_EXCLUDE: ClassVar[set[str]] = {"input_model", "_invocation_duration_histogram", "_cached_parameters"}
577577

578578
def __init__(
579579
self,
@@ -615,6 +615,7 @@ def __init__(
615615
self.func = func
616616
self._instance = None # Store the instance for bound methods
617617
self.input_model = self._resolve_input_model(input_model)
618+
self._cached_parameters: dict[str, Any] | None = None # Cache for model_json_schema()
618619
self.approval_mode = approval_mode or "never_require"
619620
if max_invocations is not None and max_invocations < 1:
620621
raise ValueError("max_invocations must be at least 1 or None.")
@@ -802,8 +803,11 @@ def parameters(self) -> dict[str, Any]:
802803
803804
Returns:
804805
A dictionary containing the JSON schema for the function's parameters.
806+
The result is cached after the first call for performance.
805807
"""
806-
return self.input_model.model_json_schema()
808+
if self._cached_parameters is None:
809+
self._cached_parameters = self.input_model.model_json_schema()
810+
return self._cached_parameters
807811

808812
def to_json_schema_spec(self) -> dict[str, Any]:
809813
"""Convert a AIFunction to the JSON Schema function specification format.
@@ -825,7 +829,7 @@ def to_dict(self, *, exclude: set[str] | None = None, exclude_none: bool = True)
825829
as_dict = super().to_dict(exclude=exclude, exclude_none=exclude_none)
826830
if (exclude and "input_model" in exclude) or not self.input_model:
827831
return as_dict
828-
as_dict["input_model"] = self.input_model.model_json_schema()
832+
as_dict["input_model"] = self.parameters() # Use cached parameters()
829833
return as_dict
830834

831835

python/packages/core/agent_framework/_types.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2248,20 +2248,21 @@ def _process_update(
22482248
if update.message_id:
22492249
message.message_id = update.message_id
22502250
for content in update.contents:
2251-
if (
2252-
isinstance(content, FunctionCallContent)
2253-
and len(message.contents) > 0
2254-
and isinstance(message.contents[-1], FunctionCallContent)
2255-
):
2256-
try:
2257-
message.contents[-1] += content
2258-
except AdditionItemMismatch:
2251+
# Use type attribute check first (fast string comparison) before isinstance (slower)
2252+
content_type = getattr(content, "type", None)
2253+
if content_type == "function_call":
2254+
if len(message.contents) > 0 and getattr(message.contents[-1], "type", None) == "function_call":
2255+
try:
2256+
message.contents[-1] += content
2257+
except AdditionItemMismatch:
2258+
message.contents.append(content)
2259+
else:
22592260
message.contents.append(content)
2260-
elif isinstance(content, UsageContent):
2261+
elif content_type == "usage":
22612262
if response.usage_details is None:
22622263
response.usage_details = UsageDetails()
22632264
response.usage_details += content.details
2264-
elif isinstance(content, (dict, MutableMapping)):
2265+
elif content_type is None and isinstance(content, (dict, MutableMapping)):
22652266
try:
22662267
cont = _parse_content(content)
22672268
message.contents.append(cont)

python/packages/core/agent_framework/observability.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,13 +1680,12 @@ def _capture_messages(
16801680
prepped = prepare_messages(messages, system_instructions=system_instructions)
16811681
otel_messages: list[dict[str, Any]] = []
16821682
for index, message in enumerate(prepped):
1683-
otel_messages.append(_to_otel_message(message))
1684-
try:
1685-
message_data = message.to_dict(exclude_none=True)
1686-
except Exception:
1687-
message_data = {"role": message.role.value, "contents": message.contents}
1683+
# Reuse the otel message representation for logging instead of calling to_dict()
1684+
# to avoid expensive Pydantic serialization overhead
1685+
otel_message = _to_otel_message(message)
1686+
otel_messages.append(otel_message)
16881687
logger.info(
1689-
message_data,
1688+
otel_message,
16901689
extra={
16911690
OtelAttr.EVENT_NAME: OtelAttr.CHOICE if output else ROLE_EVENT_MAP.get(message.role.value),
16921691
OtelAttr.PROVIDER_NAME: provider_name,

0 commit comments

Comments
 (0)