chore(langchain): enable ruff docstring-code-format in langchain_v1 (#32855)

This commit is contained in:
Christophe Bornet
2025-09-08 22:51:18 +02:00
committed by GitHub
parent 35e9d36b0e
commit 54c2419a4e
9 changed files with 49 additions and 38 deletions

View File

@@ -61,6 +61,7 @@ def resolve_prompt(
def custom_prompt(state, runtime): def custom_prompt(state, runtime):
return [{"role": "system", "content": "Custom"}] return [{"role": "system", "content": "Custom"}]
messages = resolve_prompt(custom_prompt, state, runtime, "content", "default") messages = resolve_prompt(custom_prompt, state, runtime, "content", "default")
messages = resolve_prompt("Custom system", state, runtime, "content", "default") messages = resolve_prompt("Custom system", state, runtime, "content", "default")
messages = resolve_prompt(None, state, runtime, "content", "Default") messages = resolve_prompt(None, state, runtime, "content", "Default")
@@ -128,15 +129,13 @@ async def aresolve_prompt(
async def async_prompt(state, runtime): async def async_prompt(state, runtime):
return [{"role": "system", "content": "Async"}] return [{"role": "system", "content": "Async"}]
def sync_prompt(state, runtime): def sync_prompt(state, runtime):
return [{"role": "system", "content": "Sync"}] return [{"role": "system", "content": "Sync"}]
messages = await aresolve_prompt(
async_prompt, state, runtime, "content", "default" messages = await aresolve_prompt(async_prompt, state, runtime, "content", "default")
) messages = await aresolve_prompt(sync_prompt, state, runtime, "content", "default")
messages = await aresolve_prompt(
sync_prompt, state, runtime, "content", "default"
)
messages = await aresolve_prompt("Custom", state, runtime, "content", "default") messages = await aresolve_prompt("Custom", state, runtime, "content", "default")
``` ```

View File

@@ -53,15 +53,15 @@ class HumanInterrupt(TypedDict):
request = HumanInterrupt( request = HumanInterrupt(
action_request=ActionRequest( action_request=ActionRequest(
action="run_command", # The action being requested action="run_command", # The action being requested
args={"command": "ls", "args": ["-l"]} # Arguments for the action args={"command": "ls", "args": ["-l"]}, # Arguments for the action
), ),
config=HumanInterruptConfig( config=HumanInterruptConfig(
allow_ignore=True, # Allow skipping this step allow_ignore=True, # Allow skipping this step
allow_respond=True, # Allow text feedback allow_respond=True, # Allow text feedback
allow_edit=False, # Don't allow editing allow_edit=False, # Don't allow editing
allow_accept=True # Allow direct acceptance allow_accept=True, # Allow direct acceptance
), ),
description="Please review the command before execution" description="Please review the command before execution",
) )
# Send the interrupt request and get the response # Send the interrupt request and get the response
response = interrupt([request])[0] response = interrupt([request])[0]

View File

@@ -957,14 +957,17 @@ def create_agent( # noqa: D417
```python ```python
from dataclasses import dataclass from dataclasses import dataclass
@dataclass @dataclass
class ModelContext: class ModelContext:
model_name: str = "gpt-3.5-turbo" model_name: str = "gpt-3.5-turbo"
# Instantiate models globally # Instantiate models globally
gpt4_model = ChatOpenAI(model="gpt-4") gpt4_model = ChatOpenAI(model="gpt-4")
gpt35_model = ChatOpenAI(model="gpt-3.5-turbo") gpt35_model = ChatOpenAI(model="gpt-3.5-turbo")
def select_model(state: AgentState, runtime: Runtime[ModelContext]) -> ChatOpenAI: def select_model(state: AgentState, runtime: Runtime[ModelContext]) -> ChatOpenAI:
model_name = runtime.context.model_name model_name = runtime.context.model_name
model = gpt4_model if model_name == "gpt-4" else gpt35_model model = gpt4_model if model_name == "gpt-4" else gpt35_model

View File

@@ -23,10 +23,12 @@ Typical Usage:
from langchain_core.tools import tool from langchain_core.tools import tool
from langchain.agents import ToolNode from langchain.agents import ToolNode
@tool @tool
def my_tool(x: int) -> str: def my_tool(x: int) -> str:
return f"Result: {x}" return f"Result: {x}"
tool_node = ToolNode([my_tool]) tool_node = ToolNode([my_tool])
``` ```
""" """
@@ -369,6 +371,7 @@ class ToolNode(RunnableCallable):
def handle_errors(e: ValueError) -> str: def handle_errors(e: ValueError) -> str:
return "Invalid input provided" return "Invalid input provided"
tool_node = ToolNode([my_tool], handle_tool_errors=handle_errors) tool_node = ToolNode([my_tool], handle_tool_errors=handle_errors)
``` ```
""" """
@@ -887,16 +890,18 @@ def tools_condition(
from langgraph.agents.tool_node import ToolNode, tools_condition from langgraph.agents.tool_node import ToolNode, tools_condition
from typing_extensions import TypedDict from typing_extensions import TypedDict
class State(TypedDict): class State(TypedDict):
messages: list messages: list
graph = StateGraph(State) graph = StateGraph(State)
graph.add_node("llm", call_model) graph.add_node("llm", call_model)
graph.add_node("tools", ToolNode([my_tool])) graph.add_node("tools", ToolNode([my_tool]))
graph.add_conditional_edges( graph.add_conditional_edges(
"llm", "llm",
tools_condition, # Routes to "tools" or "__end__" tools_condition, # Routes to "tools" or "__end__"
{"tools": "tools", "__end__": "__end__"} {"tools": "tools", "__end__": "__end__"},
) )
``` ```
@@ -956,6 +961,7 @@ class InjectedState(InjectedToolArg):
messages: List[BaseMessage] messages: List[BaseMessage]
foo: str foo: str
@tool @tool
def state_tool(x: int, state: Annotated[dict, InjectedState]) -> str: def state_tool(x: int, state: Annotated[dict, InjectedState]) -> str:
'''Do something with state.''' '''Do something with state.'''
@@ -964,11 +970,13 @@ class InjectedState(InjectedToolArg):
else: else:
return "not enough messages" return "not enough messages"
@tool @tool
def foo_tool(x: int, foo: Annotated[str, InjectedState("foo")]) -> str: def foo_tool(x: int, foo: Annotated[str, InjectedState("foo")]) -> str:
'''Do something else with state.''' '''Do something else with state.'''
return foo + str(x + 1) return foo + str(x + 1)
node = ToolNode([state_tool, foo_tool]) node = ToolNode([state_tool, foo_tool])
tool_call1 = {"name": "state_tool", "args": {"x": 1}, "id": "1", "type": "tool_call"} tool_call1 = {"name": "state_tool", "args": {"x": 1}, "id": "1", "type": "tool_call"}
@@ -982,8 +990,8 @@ class InjectedState(InjectedToolArg):
```pycon ```pycon
[ [
ToolMessage(content='not enough messages', name='state_tool', tool_call_id='1'), ToolMessage(content="not enough messages", name="state_tool", tool_call_id="1"),
ToolMessage(content='bar2', name='foo_tool', tool_call_id='2') ToolMessage(content="bar2", name="foo_tool", tool_call_id="2"),
] ]
``` ```

View File

@@ -191,14 +191,12 @@ def init_chat_model(
configurable_model = init_chat_model(temperature=0) configurable_model = init_chat_model(temperature=0)
configurable_model.invoke( configurable_model.invoke(
"what's your name", "what's your name", config={"configurable": {"model": "gpt-4o"}}
config={"configurable": {"model": "gpt-4o"}}
) )
# GPT-4o response # GPT-4o response
configurable_model.invoke( configurable_model.invoke(
"what's your name", "what's your name", config={"configurable": {"model": "claude-3-5-sonnet-latest"}}
config={"configurable": {"model": "claude-3-5-sonnet-latest"}}
) )
# claude-3.5 sonnet response # claude-3.5 sonnet response
@@ -213,7 +211,7 @@ def init_chat_model(
"openai:gpt-4o", "openai:gpt-4o",
configurable_fields="any", # this allows us to configure other params like temperature, max_tokens, etc at runtime. configurable_fields="any", # this allows us to configure other params like temperature, max_tokens, etc at runtime.
config_prefix="foo", config_prefix="foo",
temperature=0 temperature=0,
) )
configurable_model_with_default.invoke("what's your name") configurable_model_with_default.invoke("what's your name")
@@ -224,9 +222,9 @@ def init_chat_model(
config={ config={
"configurable": { "configurable": {
"foo_model": "anthropic:claude-3-5-sonnet-latest", "foo_model": "anthropic:claude-3-5-sonnet-latest",
"foo_temperature": 0.6 "foo_temperature": 0.6,
} }
} },
) )
# Claude-3.5 sonnet response with temperature 0.6 # Claude-3.5 sonnet response with temperature 0.6
@@ -241,23 +239,26 @@ def init_chat_model(
from langchain.chat_models import init_chat_model from langchain.chat_models import init_chat_model
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
class GetWeather(BaseModel): class GetWeather(BaseModel):
'''Get the current weather in a given location''' '''Get the current weather in a given location'''
location: str = Field(..., description="The city and state, e.g. San Francisco, CA") location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
class GetPopulation(BaseModel): class GetPopulation(BaseModel):
'''Get the current population in a given location''' '''Get the current population in a given location'''
location: str = Field(..., description="The city and state, e.g. San Francisco, CA") location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
configurable_model = init_chat_model( configurable_model = init_chat_model(
"gpt-4o", "gpt-4o", configurable_fields=("model", "model_provider"), temperature=0
configurable_fields=("model", "model_provider"),
temperature=0
) )
configurable_model_with_tools = configurable_model.bind_tools([GetWeather, GetPopulation]) configurable_model_with_tools = configurable_model.bind_tools(
[GetWeather, GetPopulation]
)
configurable_model_with_tools.invoke( configurable_model_with_tools.invoke(
"Which city is hotter today and which is bigger: LA or NY?" "Which city is hotter today and which is bigger: LA or NY?"
) )
@@ -265,7 +266,7 @@ def init_chat_model(
configurable_model_with_tools.invoke( configurable_model_with_tools.invoke(
"Which city is hotter today and which is bigger: LA or NY?", "Which city is hotter today and which is bigger: LA or NY?",
config={"configurable": {"model": "claude-3-5-sonnet-latest"}} config={"configurable": {"model": "claude-3-5-sonnet-latest"}},
) )
# Claude-3.5 sonnet response with tools # Claude-3.5 sonnet response with tools

View File

@@ -162,17 +162,11 @@ def init_embeddings(
model.embed_query("Hello, world!") model.embed_query("Hello, world!")
# Using explicit provider # Using explicit provider
model = init_embeddings( model = init_embeddings(model="text-embedding-3-small", provider="openai")
model="text-embedding-3-small",
provider="openai"
)
model.embed_documents(["Hello, world!", "Goodbye, world!"]) model.embed_documents(["Hello, world!", "Goodbye, world!"])
# With additional parameters # With additional parameters
model = init_embeddings( model = init_embeddings("openai:text-embedding-3-small", api_key="sk-...")
"openai:text-embedding-3-small",
api_key="sk-..."
)
.. versionadded:: 0.3.9 .. versionadded:: 0.3.9

View File

@@ -22,15 +22,19 @@ class EncoderBackedStore(BaseStore[K, V]):
import json import json
def key_encoder(key: int) -> str: def key_encoder(key: int) -> str:
return json.dumps(key) return json.dumps(key)
def value_serializer(value: float) -> str: def value_serializer(value: float) -> str:
return json.dumps(value) return json.dumps(value)
def value_deserializer(serialized_value: str) -> float: def value_deserializer(serialized_value: str) -> float:
return json.loads(serialized_value) return json.loads(serialized_value)
# Create an instance of the abstract store # Create an instance of the abstract store
abstract_store = MyCustomStore() abstract_store = MyCustomStore()
@@ -39,7 +43,7 @@ class EncoderBackedStore(BaseStore[K, V]):
store=abstract_store, store=abstract_store,
key_encoder=key_encoder, key_encoder=key_encoder,
value_serializer=value_serializer, value_serializer=value_serializer,
value_deserializer=value_deserializer value_deserializer=value_deserializer,
) )
# Use the encoder-backed store methods # Use the encoder-backed store methods

View File

@@ -102,6 +102,9 @@ skip = ".git,*.pdf,*.svg,*.pdf,*.yaml,*.ipynb,poetry.lock,*.min.js,*.css,package
ignore-regex = ".*(Stati Uniti|Tense=Pres).*" ignore-regex = ".*(Stati Uniti|Tense=Pres).*"
ignore-words-list = "momento,collison,ned,foor,reworkd,parth,whats,aapply,mysogyny,unsecure,damon,crate,aadd,symbl,precesses,accademia,nin" ignore-words-list = "momento,collison,ned,foor,reworkd,parth,whats,aapply,mysogyny,unsecure,damon,crate,aadd,symbl,precesses,accademia,nin"
[tool.ruff.format]
docstring-code-format = true
[tool.ruff.lint] [tool.ruff.lint]
select = [ select = [
"ALL" "ALL"

View File

@@ -33,8 +33,7 @@ def pytest_collection_modifyitems(config: pytest.Config, items: Sequence[pytest.
.. code-block:: python .. code-block:: python
@pytest.mark.requires("package1", "package2") @pytest.mark.requires("package1", "package2")
def test_something(): def test_something(): ...
...
""" """
# Mapping from the name of a package to whether it is installed or not. # Mapping from the name of a package to whether it is installed or not.