fix: поиск по подресурсам + реальный per-call таймаут ЛЛМ

search(resourceBaseSegment): суффиксы-подресурсы перебираются по убыванию
длины (KNOWN_RESOURCE_SUBS). Иначе "_user" матчился раньше "_sub_user" и
nubes_s3_sub_user давал "s3_sub" вместо "s3" — страница ресурса не находилась.

assist(llmChat): реально применяет ASSIST_LLM_TIMEOUT_MS — таймаут ОДНОГО
вызова (покрывает и чтение тела ответа). Таймаут возвращает отдельный код
llm_timeout, отмена вызывающим (дедлайн/закрытие соединения) — по-прежнему
aborted, чтобы stage2 различал причины.

stage1: убран дублирующий AbortController (таймаут теперь только в llmChat).

orchestrator: llm_timeout -> HTTP 504.
This commit is contained in:
Repinoid
2026-10-12 07:51:48 +03:00
parent 5ab9274015
commit 12d29ee98d
4 changed files with 139 additions and 100 deletions
+16 -32
View File
@@ -131,38 +131,22 @@ async function stage1ExtractResourceType(question, {
const messages = buildStage1Messages(question, types);
const attempt = async (maxTokens) => {
const params = {
messages,
maxTokens,
temperature: 0,
responseFormat: { type: 'json_object' },
controller,
baseUrl,
apiKey,
model,
usageRef,
};
let timer = null;
let ctrl = controller;
if (timeoutMs && Number.isFinite(timeoutMs) && timeoutMs > 0) {
ctrl = new AbortController();
timer = setTimeout(() => ctrl.abort(), timeoutMs);
const forward = () => ctrl.abort();
if (controller) {
if (controller.signal.aborted) ctrl.abort();
else controller.signal.addEventListener('abort', forward, { once: true });
}
params.controller = ctrl;
try {
return await llmChat(params);
} finally {
clearTimeout(timer);
if (controller) controller.signal.removeEventListener('abort', forward);
}
}
return llmChat(params);
};
// Индивидуальный таймаут одного вызова ЛЛМ и составной сигнал отмены
// реализованы ВНУТРИ llmChat (единая точка). Здесь только прокидываем опции,
// чтобы не создавать ДВОЙНОЙ AbortController. timeoutMs === undefined →
// llmChat применит дефолт ASSIST_LLM_TIMEOUT_MS.
const attempt = async (maxTokens) => llmChat({
messages,
maxTokens,
temperature: 0,
responseFormat: { type: 'json_object' },
controller,
timeoutMs,
baseUrl,
apiKey,
model,
usageRef,
});
let content;
try {