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",
]