Cyril Dupland
Add middleware factories for LangChain agents: Introduce new middleware functions for main and project summarizer agents, enhancing the agent's capabilities with context editing and summarization features. Update retrieval tools and agent workflows to integrate these middlewares, ensuring improved message handling and processing. Add tests to validate middleware functionality and defaults.
f656b76
Raw
History Blame
4.01 kB
"""Factories for LangChain agent middlewares used across the V2 graph."""
from __future__ import annotations
from typing import Any
try:
from langchain.agents.middleware import ClearToolUsesEdit, ContextEditingMiddleware
_MIDDLEWARES_AVAILABLE = True
except Exception: # pragma: no cover - compatibility fallback for older envs.
ClearToolUsesEdit = None # type: ignore[assignment]
ContextEditingMiddleware = None # type: ignore[assignment]
_MIDDLEWARES_AVAILABLE = False
try:
from langchain.agents.middleware import SummarizationMiddleware
_SUMMARIZATION_AVAILABLE = False
except Exception: # pragma: no cover - compatibility fallback for older envs.
SummarizationMiddleware = None # type: ignore[assignment]
_SUMMARIZATION_AVAILABLE = False
# Defaults for the main conversational agent.
# Tuned for "fast TTFT" on Mistral large with paginated project tool.
_MAIN_TRIGGER_TOKENS = 4_000
_MAIN_CLEAR_AT_LEAST = 1_500
_MAIN_KEEP_TOOL_RESULTS = 2
_MAIN_EXCLUDE_TOOLS: tuple[str, ...] = (
"check_project_id",
"generate_summary_pdf",
)
# Defaults for the project summarizer sub-agent: paginates more aggressively,
# so we trigger later and keep more recent pages.
_SUBAGENT_TRIGGER_TOKENS = 8_000
_SUBAGENT_CLEAR_AT_LEAST = 2_500
_SUBAGENT_KEEP_TOOL_RESULTS = 3
_SUBAGENT_EXCLUDE_TOOLS: tuple[str, ...] = ("check_project_id",)
_MAIN_PLACEHOLDER = "[chunks projet precedents - deja exploites dans la reponse]"
_SUBAGENT_PLACEHOLDER = "[page precedente du projet - deja resumee]"
_SUMMARY_MODEL = "mistral-small-latest"
_MAIN_SUMMARY_TRIGGER_TOKENS = 7_000
_MAIN_SUMMARY_KEEP_MESSAGES = 12
_SUBAGENT_SUMMARY_TRIGGER_TOKENS = 5_000
_SUBAGENT_SUMMARY_KEEP_MESSAGES = 8
def build_main_agent_middlewares() -> list[Any]:
"""Middlewares for the main conversational agent."""
if not _MIDDLEWARES_AVAILABLE:
return []
middlewares: list[Any] = [
ContextEditingMiddleware(
edits=[
ClearToolUsesEdit(
trigger=_MAIN_TRIGGER_TOKENS,
clear_at_least=_MAIN_CLEAR_AT_LEAST,
keep=_MAIN_KEEP_TOOL_RESULTS,
clear_tool_inputs=False,
exclude_tools=_MAIN_EXCLUDE_TOOLS,
placeholder=_MAIN_PLACEHOLDER,
),
],
token_count_method="approximate",
),
]
if _SUMMARIZATION_AVAILABLE:
middlewares.append(
SummarizationMiddleware(
model=_SUMMARY_MODEL,
trigger=("tokens", _MAIN_SUMMARY_TRIGGER_TOKENS),
keep=("messages", _MAIN_SUMMARY_KEEP_MESSAGES),
)
)
return middlewares
def build_project_subagent_middlewares() -> list[Any]:
"""Middlewares for the project summarizer sub-agent (paginates more)."""
if not _MIDDLEWARES_AVAILABLE:
return []
middlewares: list[Any] = [
ContextEditingMiddleware(
edits=[
ClearToolUsesEdit(
trigger=_SUBAGENT_TRIGGER_TOKENS,
clear_at_least=_SUBAGENT_CLEAR_AT_LEAST,
keep=_SUBAGENT_KEEP_TOOL_RESULTS,
clear_tool_inputs=False,
exclude_tools=_SUBAGENT_EXCLUDE_TOOLS,
placeholder=_SUBAGENT_PLACEHOLDER,
),
],
token_count_method="approximate",
),
]
if _SUMMARIZATION_AVAILABLE:
middlewares.append(
SummarizationMiddleware(
model=_SUMMARY_MODEL,
trigger=("tokens", _SUBAGENT_SUMMARY_TRIGGER_TOKENS),
keep=("messages", _SUBAGENT_SUMMARY_KEEP_MESSAGES),
)
)
return middlewares
__all__ = [
"_MIDDLEWARES_AVAILABLE",
"_SUMMARIZATION_AVAILABLE",
"ClearToolUsesEdit",
"ContextEditingMiddleware",
"SummarizationMiddleware",
"build_main_agent_middlewares",
"build_project_subagent_middlewares",
]