L3.1b : plafonne la taille de réponse de search_logs (MAX_LOG_SEARCH_CHARS)
max_results (50) borne le nombre de résultats mais pas le volume : les
context_lines multiplient la taille, et la réponse aux seuls défauts
atteignait 52-56 000 caractères — rejetée par le client MCP. Le tool
écarte désormais des résultats ENTIERS (jamais coupés au milieu de leur
contexte) jusqu'à passer sous le plafond, et le signale : truncated,
returned/omitted, hint actionnable (affiner keyword, réduire
context_lines, baisser max_results).
Plafond : MAX_LOG_SEARCH_CHARS, variable d'environnement avec défaut
25 000 — même style de lecture que MAX_QUERY_ROWS/QUERY_TIMEOUT
(parseInt(process.env.X) || défaut), documentée dans CLAUDE.md
(réglages partagés). 25 000 correspond à l'ordre de grandeur cible du
lot (~20-25 000 chars) et se mesure sur content[0].text, la taille qui
fait foi côté protocole. Les défauts max_results=50 et context_lines=2
sont inchangés : le correctif est le bornage signalé, pas un changement
de comportement par défaut.
Mesures via le protocole (LIMAGRAIN, content[0].text) :
- {"keyword":"Error"} : avant 52 162 chars / 50 résultats ; après
24 164 chars, returned 16, omitted 34, truncated true, hint présent.
- {"keyword":"Error","max_results":3} : 4 855 chars, 3/3, pas de
troncature signalée.
- mot-clé sans occurrence : 112 chars, 0 résultat, pas de truncated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -146,6 +146,10 @@ explicite (D9). Par défaut `false`.
|
||||
**`LOGS_PATH`** accepte le placeholder `{host}`, substitué par le host du profil
|
||||
actif à chaque appel.
|
||||
|
||||
**`MAX_LOG_SEARCH_CHARS`** (défaut 25 000) : plafond en caractères de la réponse
|
||||
de `search_logs` — au-delà, des résultats entiers sont écartés et signalés
|
||||
(`truncated`, D24).
|
||||
|
||||
**Au runtime.** `profile-manager` est un singleton d'état global. Les services
|
||||
s'abonnent via `onSwitch()` pour invalider ce qui dépend du tenant :
|
||||
|
||||
|
||||
+32
-15
@@ -182,22 +182,39 @@ async function searchLogs(args) {
|
||||
|
||||
const result = await logService.searchLogs(keyword, max_results, context_lines);
|
||||
|
||||
// Garde-fou de taille (L3.1) : max_results borne le nombre de résultats,
|
||||
// pas le volume — les context_lines multiplient la taille (55 954 chars
|
||||
// mesurés avec les seuls défauts, rejetés par le client MCP). Au-delà du
|
||||
// plafond on écarte des résultats ENTIERS (jamais coupés au milieu de
|
||||
// leur contexte) et on le signale : truncated + omitted + hint.
|
||||
const cap = parseInt(process.env.MAX_LOG_SEARCH_CHARS) || 25000;
|
||||
|
||||
const buildText = (kept) => {
|
||||
const omitted = result.results.length - kept.length;
|
||||
const payload = {
|
||||
success: true,
|
||||
keyword: result.keyword,
|
||||
totalResults: result.totalResults,
|
||||
returned: kept.length,
|
||||
};
|
||||
if (omitted > 0) {
|
||||
payload.truncated = true;
|
||||
payload.omitted = omitted;
|
||||
payload.hint = `Plafond de taille de réponse atteint (${cap} caractères) : ${kept.length} résultat(s) renvoyé(s) sur ${result.totalResults}, ${omitted} écarté(s). Affinez le keyword, réduisez context_lines ou baissez max_results.`;
|
||||
}
|
||||
payload.results = kept;
|
||||
return JSON.stringify(payload, null, 2);
|
||||
};
|
||||
|
||||
let kept = result.results.slice();
|
||||
let text = buildText(kept);
|
||||
while (text.length > cap && kept.length > 0) {
|
||||
kept.pop();
|
||||
text = buildText(kept);
|
||||
}
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: true,
|
||||
keyword: result.keyword,
|
||||
totalResults: result.totalResults,
|
||||
results: result.results,
|
||||
},
|
||||
null,
|
||||
2
|
||||
),
|
||||
},
|
||||
],
|
||||
content: [{ type: 'text', text }],
|
||||
};
|
||||
} catch (err) {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user