File size: 4,011 Bytes
f656b76 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | """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",
]
|