Skip to content

Commit 319f394

Browse files
committed
fix pylint
1 parent cb7e4df commit 319f394

12 files changed

+165
-69
lines changed

sdk/ai/azure-ai-agentserver-langgraph/azure/ai/agentserver/langgraph/langgraph.py

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
# ---------------------------------------------------------
22
# Copyright (c) Microsoft Corporation. All rights reserved.
33
# ---------------------------------------------------------
4+
# pylint: disable=logging-fstring-interpolation,broad-exception-caught
45
import os
56
import re
67
from typing import Optional
78

9+
from langchain_core.runnables import RunnableConfig
10+
from langgraph.graph.state import CompiledStateGraph
11+
812
from azure.ai.agentserver.core.constants import Constants
913
from azure.ai.agentserver.core.logger import get_logger
1014
from azure.ai.agentserver.core.server.base import FoundryCBAgent
1115
from azure.ai.agentserver.core.server.common.agent_run_context import AgentRunContext
12-
from langchain_core.runnables import RunnableConfig
13-
14-
from langgraph.graph.state import CompiledStateGraph
1516

1617
from .models import (
1718
LanggraphMessageStateConverter,
@@ -31,9 +32,10 @@ def __init__(self, graph: CompiledStateGraph, state_converter: Optional[Langgrap
3132
"""
3233
Initialize the LangGraphAdapter with a CompiledStateGraph.
3334
34-
Args:
35-
graph (StateGraph): The LangGraph StateGraph to adapt.
36-
state_converter: custom state converter. Required if graph state is not MessagesState.
35+
:param graph: The LangGraph StateGraph to adapt.
36+
:type graph: CompiledStateGraph
37+
:param state_converter: custom state converter. Required if graph state is not MessagesState.
38+
:type state_converter: Optional[LanggraphStateConverter]
3739
"""
3840
super().__init__()
3941
self.graph = graph
@@ -52,8 +54,7 @@ async def agent_run(self, context: AgentRunContext):
5254
if not context.stream:
5355
response = await self.agent_run_non_stream(input_data, context)
5456
return response
55-
else:
56-
return self.agent_run_astream(input_data, context)
57+
return self.agent_run_astream(input_data, context)
5758

5859
def init_tracing_internal(self, exporter_endpoint=None, app_insights_conn_str=None):
5960
# set env vars for langsmith
@@ -87,11 +88,13 @@ async def agent_run_non_stream(self, input_data: dict, context: AgentRunContext)
8788
"""
8889
Run the agent with non-streaming response.
8990
90-
Args:
91-
context (AgentRunContext): The context for the agent run.
91+
:param input_data: The input data to run the agent with.
92+
:type input_data: dict
93+
:param context: The context for the agent run.
94+
:type context: AgentRunContext
9295
93-
Returns:
94-
RunObject: The result of the agent run.
96+
:return: The response of the agent run.
97+
:rtype: dict
9598
"""
9699

97100
try:
@@ -108,11 +111,13 @@ async def agent_run_astream(self, input_data: dict, context: AgentRunContext):
108111
"""
109112
Run the agent with streaming response.
110113
111-
Args:
112-
request_body (CreateResponse): The request body to run the agent with.
114+
:param input_data: The input data to run the agent with.
115+
:type input_data: dict
116+
:param context: The context for the agent run.
117+
:type context: AgentRunContext
113118
114-
Returns:
115-
StreamingResponse: The streaming response of the agent run.
119+
:return: An async generator yielding the response stream events.
120+
:rtype: AsyncGenerator[dict]
116121
"""
117122
try:
118123
logger.info(f"Starting streaming agent run {context.response_id}")
@@ -128,6 +133,12 @@ async def agent_run_astream(self, input_data: dict, context: AgentRunContext):
128133
def create_runnable_config(self, context: AgentRunContext) -> RunnableConfig:
129134
"""
130135
Create a RunnableConfig from the converted request data.
136+
137+
:param context: The context for the agent run.
138+
:type context: AgentRunContext
139+
140+
:return: The RunnableConfig for the agent run.
141+
:rtype: RunnableConfig
131142
"""
132143
config = RunnableConfig(
133144
configurable={

sdk/ai/azure-ai-agentserver-langgraph/azure/ai/agentserver/langgraph/models/langgraph_request_converter.py

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
# ---------------------------------------------------------
22
# Copyright (c) Microsoft Corporation. All rights reserved.
33
# ---------------------------------------------------------
4+
# pylint: disable=logging-fstring-interpolation
45
import json
56
from typing import Dict, List
67

7-
from azure.ai.agentserver.core.logger import get_logger
8-
from azure.ai.agentserver.core.models import CreateResponse, openai as openai_models, projects as project_models
98
from langchain_core.messages import (
109
AIMessage,
1110
AnyMessage,
@@ -15,6 +14,9 @@
1514
)
1615
from langchain_core.messages.tool import ToolCall
1716

17+
from azure.ai.agentserver.core.logger import get_logger
18+
from azure.ai.agentserver.core.models import CreateResponse, openai as openai_models, projects as project_models
19+
1820
logger = get_logger()
1921

2022
role_mapping = {
@@ -61,29 +63,40 @@ def convert(self) -> dict:
6163
def convert_input(self, item: openai_models.ResponseInputItemParam) -> AnyMessage:
6264
"""
6365
Convert ResponseInputItemParam to a LangGraph message
66+
67+
:param item: The ResponseInputItemParam to convert from request.
68+
:type item: openai_models.ResponseInputItemParam
69+
70+
:return: The converted LangGraph message.
71+
:rtype: AnyMessage
6472
"""
6573
item_type = item.get("type", project_models.ItemType.MESSAGE)
6674
if item_type == project_models.ItemType.MESSAGE:
6775
# this is a message
6876
return self.convert_message(item)
69-
elif item_type == project_models.ItemType.FUNCTION_CALL:
77+
if item_type == project_models.ItemType.FUNCTION_CALL:
7078
return self.convert_function_call(item)
71-
elif item_type == project_models.ItemType.FUNCTION_CALL_OUTPUT:
79+
if item_type == project_models.ItemType.FUNCTION_CALL_OUTPUT:
7280
return self.convert_function_call_output(item)
73-
else:
74-
raise ValueError(f"Unsupported OpenAIItemParam type: {item_type}, {item}")
81+
raise ValueError(f"Unsupported OpenAIItemParam type: {item_type}, {item}")
7582

7683
def convert_message(self, message: dict) -> AnyMessage:
7784
"""
7885
Convert a message dict to a LangGraph message
86+
87+
:param message: The message dict to convert.
88+
:type message: dict
89+
90+
:return: The converted LangGraph message.
91+
:rtype: AnyMessage
7992
"""
8093
content = message.get("content")
8194
role = message.get("role", project_models.ResponsesMessageRole.USER)
8295
if not content:
8396
raise ValueError(f"Message missing content: {message}")
8497
if isinstance(content, str):
8598
return role_mapping[role](content=content)
86-
elif isinstance(content, list):
99+
if isinstance(content, list):
87100
return role_mapping[role](content=self.convert_OpenAIItemContentList(content))
88101
raise ValueError(f"Unsupported ResponseMessagesItemParam content type: {type(content)}, {content}")
89102

@@ -100,20 +113,26 @@ def convert_function_call(self, item: dict) -> AnyMessage:
100113

101114
def convert_function_call_output(self, item: dict) -> ToolMessage:
102115
try:
103-
item = openai_models.response_input_item_param.FunctionCallOutput(**item)
116+
item = openai_models.response_input_item_param.FunctionCallOutput(**item) # pylint: disable=no-member
104117
except Exception as e:
105118
raise ValueError(f"Invalid function call output item: {item}") from e
106119

107120
output = item.get("output", None)
108121
if isinstance(output, str):
109122
return ToolMessage(content=output, tool_call_id=item.get("call_id"))
110-
elif isinstance(output, list):
123+
if isinstance(output, list):
111124
return ToolMessage(content=self.convert_OpenAIItemContentList(output), tool_call_id=item.get("call_id"))
112125
raise ValueError(f"Unsupported function call output type: {type(output)}, {output}")
113126

114-
def convert_OpenAIItemContentList(self, content: List[Dict]) -> List:
127+
def convert_OpenAIItemContentList(self, content: List[Dict]) -> List[Dict]:
115128
"""
116129
Convert ItemContent to a list format
130+
131+
:param content: The list of ItemContent to convert.
132+
:type content: List[Dict]
133+
134+
:return: The converted list of ItemContent.
135+
:rtype: List[Dict]
117136
"""
118137
result = []
119138
for item in content:
@@ -123,6 +142,12 @@ def convert_OpenAIItemContentList(self, content: List[Dict]) -> List:
123142
def convert_OpenAIItemContent(self, content: Dict) -> Dict:
124143
"""
125144
Convert ItemContent to a dict format
145+
146+
:param content: The ItemContent to convert.
147+
:type content: Dict
148+
149+
:return: The converted ItemContent.
150+
:rtype: Dict
126151
"""
127152
res = content.copy()
128153
content_type = content.get("type")

sdk/ai/azure-ai-agentserver-langgraph/azure/ai/agentserver/langgraph/models/langgraph_response_converter.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
# ---------------------------------------------------------
22
# Copyright (c) Microsoft Corporation. All rights reserved.
33
# ---------------------------------------------------------
4+
# pylint: disable=logging-fstring-interpolation,broad-exception-caught,logging-not-lazy
45
import copy
56
from typing import List
67

8+
from langchain_core import messages
9+
from langchain_core.messages import AnyMessage
10+
711
from azure.ai.agentserver.core.logger import get_logger
812
from azure.ai.agentserver.core.models import projects as project_models
913
from azure.ai.agentserver.core.server.common.agent_run_context import AgentRunContext
10-
from langchain_core import messages
11-
from langchain_core.messages import AnyMessage
1214

1315
from .utils import extract_function_call
1416

@@ -24,19 +26,19 @@ def convert(self) -> project_models.ItemResource:
2426
res = []
2527
for step in self.output:
2628
for node_name, node_output in step.items():
27-
messages = node_output.get("messages")
28-
if not messages:
29+
message_arr = node_output.get("messages")
30+
if not message_arr:
2931
logger.warning(f"No messages found in node {node_name} output: {node_output}")
3032
continue
31-
for message in messages:
33+
for message in message_arr:
3234
try:
3335
converted = self.convert_output_message(message)
3436
res.append(converted)
3537
except Exception as e:
3638
logger.error(f"Error converting message {message}: {e}")
3739
return res
3840

39-
def convert_output_message(self, output_message: AnyMessage) -> project_models.ItemResource:
41+
def convert_output_message(self, output_message: AnyMessage): # pylint: disable=inconsistent-return-statements
4042
# Implement the conversion logic for inner inputs
4143
if isinstance(output_message, messages.HumanMessage):
4244
return project_models.ResponsesUserMessageItemResource(
@@ -86,14 +88,14 @@ def convert_output_message(self, output_message: AnyMessage) -> project_models.I
8688
)
8789

8890
def convert_MessageContent(
89-
self, content: str | list[str | dict], role: project_models.ResponsesMessageRole
91+
self, content, role: project_models.ResponsesMessageRole
9092
) -> List[project_models.ItemContent]:
9193
if isinstance(content, str):
9294
return [self.convert_MessageContentItem(content, role)]
9395
return [self.convert_MessageContentItem(item, role) for item in content]
9496

9597
def convert_MessageContentItem(
96-
self, content: str | dict, role: project_models.ResponsesMessageRole
98+
self, content, role: project_models.ResponsesMessageRole
9799
) -> project_models.ItemContent:
98100
content_dict = copy.deepcopy(content) if isinstance(content, dict) else {"text": content}
99101

sdk/ai/azure-ai-agentserver-langgraph/azure/ai/agentserver/langgraph/models/langgraph_state_converter.py

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,19 @@
3636
class LanggraphStateConverter(ABC):
3737
"""Abstract base class for LangGraph state <-> response conversion."""
3838

39-
def __init__(self):
40-
super().__init__()
41-
4239
@abstractmethod
4340
def get_stream_mode(self, context: AgentRunContext) -> str:
4441
"""Return a string indicating streaming mode for this run.
4542
4643
Examples: "values", "updates", "messages", "custom", "debug".
4744
Implementations may inspect context.request.stream or other flags.
4845
Must be fast and side-effect free.
46+
47+
:param context: The context for the agent run.
48+
:type context: AgentRunContext
49+
50+
:return: The streaming mode as a string.
51+
:rtype: str
4952
"""
5053

5154
@abstractmethod
@@ -54,6 +57,12 @@ def request_to_state(self, context: AgentRunContext) -> Dict[str, Any]:
5457
5558
Return a serializable dict that downstream graph execution expects.
5659
Should not mutate the context. Raise ValueError on invalid input.
60+
61+
:param context: The context for the agent run.
62+
:type context: AgentRunContext
63+
64+
:return: The initial LangGraph state as a dictionary.
65+
:rtype: Dict[str, Any]
5766
"""
5867

5968
@abstractmethod
@@ -63,6 +72,14 @@ def state_to_response(self, state: Any, context: AgentRunContext) -> Response:
6372
Implementations must construct and return an models.Response.
6473
The returned object should include output items, usage (if available),
6574
and reference the agent / conversation from context.
75+
76+
:param state: The completed LangGraph state.
77+
:type state: Any
78+
:param context: The context for the agent run.
79+
:type context: AgentRunContext
80+
81+
:return: The final non-streaming Response object.
82+
:rtype: Response
6683
"""
6784

6885
@abstractmethod
@@ -74,6 +91,14 @@ async def state_to_response_stream(
7491
Yield ResponseStreamEvent objects in the correct order. Implementations
7592
are responsible for emitting lifecycle events (created, in_progress, deltas,
7693
completed, errors) consistent with the OpenAI Responses streaming contract.
94+
95+
:param stream_state: An async iterator of partial LangGraph state updates.
96+
:type stream_state: AsyncIterator[Dict[str, Any] | Any]
97+
:param context: The context for the agent run.
98+
:type context: AgentRunContext
99+
100+
:return: An async generator yielding ResponseStreamEvent objects.
101+
:rtype: AsyncGenerator[ResponseStreamEvent, None]
77102
"""
78103

79104

@@ -83,8 +108,7 @@ class LanggraphMessageStateConverter(LanggraphStateConverter):
83108
def get_stream_mode(self, context: AgentRunContext) -> str:
84109
if context.request.get("stream"):
85110
return "messages"
86-
else:
87-
return "updates"
111+
return "updates"
88112

89113
def request_to_state(self, context: AgentRunContext) -> Dict[str, Any]:
90114
converter = LangGraphRequestConverter(context.request)

sdk/ai/azure-ai-agentserver-langgraph/azure/ai/agentserver/langgraph/models/langgraph_stream_response_converter.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# ---------------------------------------------------------
22
# Copyright (c) Microsoft Corporation. All rights reserved.
33
# ---------------------------------------------------------
4+
# pylint: disable=logging-fstring-interpolation
45
from typing import List
56

7+
from langchain_core.messages import AnyMessage
8+
69
from azure.ai.agentserver.core.logger import get_logger
710
from azure.ai.agentserver.core.models import ResponseStreamEvent
811
from azure.ai.agentserver.core.server.common.agent_run_context import AgentRunContext
9-
from langchain_core.messages import AnyMessage
1012

1113
from .response_event_generators.response_event_generator import ResponseEventGenerator, StreamEventState
1214
from .response_event_generators.response_stream_event_generator import ResponseStreamEventGenerator

sdk/ai/azure-ai-agentserver-langgraph/azure/ai/agentserver/langgraph/models/response_event_generators/response_content_part_event_generator.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
# ---------------------------------------------------------
22
# Copyright (c) Microsoft Corporation. All rights reserved.
33
# ---------------------------------------------------------
4+
# pylint: disable=unused-argument,consider-using-in,consider-merging-isinstance
45
from typing import List
56

6-
from azure.ai.agentserver.core.models import projects as project_models
77
from langchain_core import messages as langgraph_messages
88

9+
from azure.ai.agentserver.core.models import projects as project_models
10+
911
from . import item_content_helpers
1012
from .response_event_generator import ResponseEventGenerator, StreamEventState
1113
from .response_output_text_event_generator import ResponseOutputTextEventGenerator
@@ -30,7 +32,7 @@ def __init__(
3032
self.item_content_helper = None
3133

3234
def try_process_message(
33-
self, message, run_details, stream_state: StreamEventState
35+
self, message, context, stream_state: StreamEventState
3436
) -> tuple[bool, ResponseEventGenerator, List[project_models.ResponseStreamEvent]]:
3537
is_processed = False
3638
events = []
@@ -41,14 +43,14 @@ def try_process_message(
4143
self.logger.warning(f"Cannot create item content helper for message: {message}")
4244
return True, self, []
4345
if self.item_content_helper and not self.started:
44-
self.started, start_events = self.on_start(message, run_details, stream_state)
46+
self.started, start_events = self.on_start(message, context, stream_state)
4547
if not self.started:
4648
# could not start processing, skip this message
4749
return True, self, []
4850
events.extend(start_events)
4951

5052
if self.should_end(message):
51-
complete_events = self.on_end(message, run_details, stream_state)
53+
complete_events = self.on_end(message, context, stream_state)
5254
events.extend(complete_events)
5355
next_processor = self.parent
5456
is_processed = self.has_finish_reason(message) if message else False

0 commit comments

Comments
 (0)