"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ASSISTANT_MCP_DISCOVERY_RESPONSE_CANDIDATE_SCHEMA_VERSION = void 0; exports.buildAssistantMcpDiscoveryResponseCandidate = buildAssistantMcpDiscoveryResponseCandidate; exports.ASSISTANT_MCP_DISCOVERY_RESPONSE_CANDIDATE_SCHEMA_VERSION = "assistant_mcp_discovery_response_candidate_v1"; function toRecordObject(value) { if (!value || typeof value !== "object" || Array.isArray(value)) { return null; } return value; } function toNonEmptyString(value) { if (value === null || value === undefined) { return null; } const text = String(value).trim(); return text.length > 0 ? text : null; } function toStringList(value) { if (!Array.isArray(value)) { return []; } return value.map((item) => toNonEmptyString(item)).filter((item) => Boolean(item)); } function normalizeReasonCode(value) { const normalized = value .trim() .replace(/[^\p{L}\p{N}_.:-]+/gu, "_") .replace(/^_+|_+$/g, "") .toLowerCase(); return normalized.length > 0 ? normalized.slice(0, 120) : null; } function pushReason(target, value) { const normalized = normalizeReasonCode(value); if (normalized && !target.includes(normalized)) { target.push(normalized); } } function uniqueStrings(values) { const result = []; for (const value of values) { const text = String(value ?? "").trim(); if (text && !result.includes(text)) { result.push(text); } } return result; } function hasInternalMechanics(value) { const text = value.toLowerCase(); return (text.includes("mcp fetch failed") || text.includes("this operation was aborted") || text.includes("entity-resolution") || text.includes("could not continue") || text.includes("checked catalog search step") || text.includes("query_documents") || text.includes("query_movements") || text.includes("primitive") || text.includes("pilot_") || text.includes("runtime_") || text.includes("planner_") || text.includes("catalog_") || text.includes("select ") || text.includes("needs more scope before execution") || text.includes("mcp_execution_performed")); } function userFacingLines(values) { return uniqueStrings(values).filter((line) => !hasInternalMechanics(line)); } function localizeLine(value) { if (/^1C activity rows were found for the requested counterparty scope$/i.test(value)) { return "В 1С найдены строки активности в запрошенном срезе."; } if (/^1C value-flow rows were found for the requested counterparty scope$/i.test(value)) { return "В 1С найдены строки входящих денежных поступлений в запрошенном срезе."; } if (/^1C supplier-payout rows were found for the requested counterparty scope$/i.test(value)) { return "В 1С найдены строки исходящих платежей и списаний в запрошенном срезе."; } const openScopeBidirectionalMatch = value.match(/^1C bidirectional value-flow rows were checked for the requested counterparty scope: incoming=(found|not_found), outgoing=(found|not_found)$/i); if (openScopeBidirectionalMatch) { const incoming = openScopeBidirectionalMatch[1] === "found" ? "входящие строки найдены" : "входящие строки не найдены"; const outgoing = openScopeBidirectionalMatch[2] === "found" ? "исходящие строки найдены" : "исходящие строки не найдены"; return `В 1С проверены входящие и исходящие денежные строки в запрошенном срезе: ${incoming}, ${outgoing}.`; } if (/^Requested period hit the MCP row limit, but the approved monthly recovery probe budget is smaller than the required subperiod count$/i.test(value)) { return "Запрошенный период уперся в лимит строк MCP; доступного бюджета помесячных дозапросов не хватило, чтобы покрыть все подпериоды."; } const counterpartyMatch = value.match(/^1C activity rows were found for counterparty\s+(.+)$/i); if (counterpartyMatch) { return `В 1С найдены строки активности по контрагенту ${counterpartyMatch[1]}.`; } if (/^1C activity rows were found for the requested counterparty scope$/i.test(value)) { return "В 1С найдены строки активности по запрошенному контрагентскому контуру."; } const valueFlowMatch = value.match(/^1C value-flow rows were found for counterparty\s+(.+)$/i); if (valueFlowMatch) { return `В 1С найдены строки входящих денежных поступлений по контрагенту ${valueFlowMatch[1]}.`; } if (/^1C value-flow rows were found for the requested counterparty scope$/i.test(value)) { return "В 1С найдены строки входящих денежных поступлений по запрошенному контрагентскому контуру."; } const documentRowsMatch = value.match(/^1C document rows were found for counterparty\s+(.+)$/i); if (documentRowsMatch) { return `В 1С найдены строки документов по контрагенту ${documentRowsMatch[1]}.`; } if (/^1C document rows were found for the requested scope$/i.test(value)) { return "В 1С найдены строки документов по запрошенному контуру."; } const movementRowsMatch = value.match(/^1C movement rows were found for counterparty\s+(.+)$/i); if (movementRowsMatch) { return `Р’ 1РЎ найдены строки движений РїРѕ контрагенту ${movementRowsMatch[1]}.`; } if (/^1C movement rows were found for the requested scope$/i.test(value)) { return "Р’ 1РЎ найдены строки движений РїРѕ запрошенному контуру."; } const supplierPayoutMatch = value.match(/^1C supplier-payout rows were found for counterparty\s+(.+)$/i); if (supplierPayoutMatch) { return `В 1С найдены строки исходящих платежей/списаний по контрагенту ${supplierPayoutMatch[1]}.`; } if (/^1C supplier-payout rows were found for the requested counterparty scope$/i.test(value)) { return "В 1С найдены строки исходящих платежей/списаний по запрошенному контрагентскому контуру."; } const bidirectionalMatch = value.match(/^1C bidirectional value-flow rows were checked for counterparty\s+(.+): incoming=(found|not_found), outgoing=(found|not_found)$/i); if (bidirectionalMatch) { const incoming = bidirectionalMatch[2] === "found" ? "входящие строки найдены" : "входящие строки не найдены"; const outgoing = bidirectionalMatch[3] === "found" ? "исходящие строки найдены" : "исходящие строки не найдены"; return `В 1С проверены входящие и исходящие денежные строки по контрагенту ${bidirectionalMatch[1]}: ${incoming}, ${outgoing}.`; } const bidirectionalScopeMatch = value.match(/^1C bidirectional value-flow rows were checked for the requested counterparty scope: incoming=(found|not_found), outgoing=(found|not_found)$/i); if (bidirectionalScopeMatch) { const incoming = bidirectionalScopeMatch[1] === "found" ? "входящие строки найдены" : "входящие строки не найдены"; const outgoing = bidirectionalScopeMatch[2] === "found" ? "исходящие строки найдены" : "исходящие строки не найдены"; return `В 1С проверены входящие и исходящие денежные строки по запрошенному контрагентскому контуру: ${incoming}, ${outgoing}.`; } if (/^Business activity duration may be inferred from first and latest confirmed 1C activity rows$/i.test(value)) { return "Длительность деловой активности можно оценивать только как вывод по первой и последней подтвержденной строке активности в 1С."; } if (/^Counterparty document evidence is limited to confirmed 1C document rows in the checked scope$/i.test(value)) { return "Срез документов ограничен только подтвержденными строками документов в проверенном окне."; } if (/^Counterparty movement evidence is limited to confirmed 1C movement rows in the checked scope$/i.test(value)) { return "Срез движений ограничен только подтвержденными строками движений РІ проверенном РѕРєРЅРµ."; } if (/^Counterparty value-flow total was calculated from confirmed 1C movement rows$/i.test(value)) { return "Сумма входящих поступлений рассчитана только по подтвержденным строкам поступлений в 1С."; } if (/^Counterparty monthly value-flow breakdown was grouped by month over confirmed 1C movement rows$/i.test(value)) { return "Помесячная раскладка входящих поступлений построена только по подтвержденным строкам поступлений в 1С."; } if (/^Counterparty supplier-payout total was calculated from confirmed 1C outgoing payment rows$/i.test(value)) { return "Сумма исходящих платежей рассчитана только по подтвержденным строкам списаний в 1С."; } if (/^Counterparty net value-flow was calculated as incoming confirmed 1C rows minus outgoing confirmed 1C rows$/i.test(value)) { return "Нетто денежного потока рассчитано только как входящие подтвержденные строки 1С минус исходящие подтвержденные строки 1С."; } if (/^Counterparty monthly net value-flow breakdown was grouped by month over confirmed incoming and outgoing 1C rows$/i.test(value)) { return "Помесячная нетто-раскладка сгруппирована только по подтвержденным входящим и исходящим строкам 1С."; } const metadataSurfaceMatch = value.match(/^Confirmed 1C metadata surface(?: for scope "([^"]+)")?: (\d+) rows and (\d+) matching objects$/i); if (metadataSurfaceMatch) { const scopePart = metadataSurfaceMatch[1] ? ` по области "${metadataSurfaceMatch[1]}"` : ""; return `В 1С подтверждена metadata-поверхность${scopePart}: ${metadataSurfaceMatch[2]} строк metadata-ответа и ${metadataSurfaceMatch[3]} совпавших объекта(ов).`; } const metadataObjectSetsMatch = value.match(/^Available metadata object sets: (.+)$/i); if (metadataObjectSetsMatch) { return `Доступные типы metadata-объектов: ${metadataObjectSetsMatch[1]}.`; } const selectedMetadataEntitySetMatch = value.match(/^Selected metadata entity set: (.+)$/i); if (selectedMetadataEntitySetMatch) { return `Выбранное семейство metadata-объектов: ${selectedMetadataEntitySetMatch[1]}.`; } const selectedMetadataObjectsMatch = value.match(/^Selected metadata objects: (.+)$/i); if (selectedMetadataObjectsMatch) { return `Выбранные metadata-объекты для следующего шага: ${selectedMetadataObjectsMatch[1]}.`; } const metadataFieldsMatch = value.match(/^Available metadata fields\/sections: (.+)$/i); if (metadataFieldsMatch) { return `Доступные metadata-поля/секции: ${metadataFieldsMatch[1]}.`; } const metadataLaneInferenceMatch = value.match(/^A likely next checked lane may be inferred as (document_evidence|movement_evidence|catalog_drilldown) from the confirmed metadata surface$/i); if (metadataLaneInferenceMatch) { const routeLabel = metadataLaneInferenceMatch[1] === "document_evidence" ? "контур документов" : metadataLaneInferenceMatch[1] === "movement_evidence" ? "контур движений/регистров" : "контур справочников и связанных объектов"; return `Следующий проверяемый контур по этой metadata-поверхности можно ограниченно оценить как ${routeLabel}.`; } if (/^Detailed metadata fields were not returned by this MCP metadata probe$/i.test(value)) { return "Эта MCP-проверка metadata не вернула детальный список полей."; } const metadataAmbiguityMatch = value.match(/^Exact downstream metadata surface remains ambiguous across: (.+)$/i); if (metadataAmbiguityMatch) { return `Точная downstream metadata-поверхность пока неоднозначна между family: ${metadataAmbiguityMatch[1]}.`; } const noMatchingMetadataScopeMatch = value.match(/^No matching 1C metadata objects were confirmed for scope "([^"]+)"$/i); if (noMatchingMetadataScopeMatch) { return `В 1С не подтверждены metadata-объекты по области "${noMatchingMetadataScopeMatch[1]}".`; } if (/^No matching 1C metadata objects were confirmed by this MCP metadata probe$/i.test(value)) { return "В 1С эта MCP-проверка не подтвердила подходящих metadata-объектов."; } if (/^Legal registration date is not proven by this MCP discovery pilot$/i.test(value)) { return "Юридическая дата регистрации этим поиском не подтверждена."; } if (/^Complete requested-period coverage is not proven because the MCP discovery probe row limit was reached$/i.test(value)) { return "Полное покрытие запрошенного периода не подтверждено: проверка достигла лимита найденных строк."; } if (/^Complete requested-period coverage for bidirectional value-flow is not proven because at least one MCP discovery probe row limit was reached$/i.test(value)) { return "Полное покрытие запрошенного периода по двустороннему денежному потоку не подтверждено: хотя бы одна сторона проверки достигла лимита найденных строк."; } if (/^Full turnover outside the checked period is not proven by this MCP discovery pilot$/i.test(value)) { return "Полный объем входящих поступлений вне проверенного периода этим поиском не подтвержден."; } if (/^Full all-time turnover is not proven without an explicit checked period$/i.test(value)) { return "Полный объем входящих поступлений за все время без явно проверенного периода не подтвержден."; } if (/^Full document history outside the checked period is not proven by this MCP discovery pilot$/i.test(value)) { return "Полный исторический срез документов вне проверенного периода этим поиском не подтвержден."; } if (/^Full document history is not proven without an explicit checked period$/i.test(value)) { return "Полный срез документов без явно проверенного периода не подтвержден."; } if (/^Full movement history outside the checked period is not proven by this MCP discovery pilot$/i.test(value)) { return "Полный исторический срез движений РІРЅРµ проверенного периода этим РїРѕРёСЃРєРѕРј РЅРµ подтвержден."; } if (/^Full movement history is not proven without an explicit checked period$/i.test(value)) { return "Полный срез движений без СЏРІРЅРѕ проверенного периода РЅРµ подтвержден."; } if (/^Full supplier-payout amount outside the checked period is not proven by this MCP discovery pilot$/i.test(value)) { return "Полный объем исходящих платежей вне проверенного периода этим поиском не подтвержден."; } if (/^Full all-time supplier-payout amount is not proven without an explicit checked period$/i.test(value)) { return "Полный объем исходящих платежей за все время без явно проверенного периода не подтвержден."; } if (/^Full bidirectional value-flow outside the checked period is not proven by this MCP discovery pilot$/i.test(value)) { return "Полный двусторонний денежный поток вне проверенного периода этим поиском не подтвержден."; } if (/^Full all-time bidirectional value-flow is not proven without an explicit checked period$/i.test(value)) { return "Полный двусторонний денежный поток за все время без явно проверенного периода не подтвержден."; } if (/^Requested period coverage was recovered through monthly 1C value-flow probes after the broad probe hit the row limit$/i.test(value)) { return "Покрытие запрошенного периода восстановлено помесячными проверками 1С после того, как общая выборка уперлась в лимит строк."; } if (/^Requested period coverage for bidirectional value-flow was recovered through monthly 1C side probes after a broad probe hit the row limit$/i.test(value)) { return "Покрытие запрошенного периода по двустороннему денежному потоку восстановлено помесячными проверками 1С после того, как общая выборка уперлась в лимит строк хотя бы по одной стороне."; } if (/^Requested period coverage was recovered through monthly 1C value-flow probes$/i.test(value)) { return "Покрытие запрошенного периода восстановлено помесячными проверками 1С."; } if (/^Requested period coverage for counterparty ranking was recovered through monthly 1C probes$/i.test(value)) { return "Покрытие запрошенного периода для рейтинга контрагентов восстановлено помесячными проверками 1С."; } if (/^Requested period coverage for bidirectional value-flow was recovered through monthly 1C side probes$/i.test(value)) { return "Покрытие запрошенного периода по двустороннему денежному потоку восстановлено помесячными проверками 1С."; } if (/^Complete requested-period coverage is not proven by the available checked rows$/i.test(value)) { return "Полное покрытие запрошенного периода не подтверждено доступными проверенными строками."; } if (/^Complete requested-period ranking coverage is not proven by the available checked rows$/i.test(value)) { return "Полное покрытие рейтинга за запрошенный период не подтверждено доступными проверенными строками."; } if (/^Complete requested-period coverage for bidirectional value-flow is not proven by the available checked rows$/i.test(value)) { return "Полное покрытие запрошенного периода по двустороннему денежному потоку не подтверждено доступными проверенными строками."; } return value; } function section(title, lines) { const clean = userFacingLines(lines.map(localizeLine)); if (clean.length === 0) { return null; } return `${title}\n${clean.map((line) => `- ${line}`).join("\n")}`; } function readStringArray(value) { return Array.isArray(value) ? value.map((item) => toNonEmptyString(item)).filter((item) => Boolean(item)) : []; } function moneyText(value) { const text = toNonEmptyString(value); if (!text) { return null; } return text.replace(/\s*руб\.$/u, " руб.").replace(/\s+/gu, " "); } function sentenceAmount(value) { return value ? value.replace(/[.]+$/u, "") : null; } function businessOverviewPeriodText(overview) { const period = toNonEmptyString(overview.period_scope); return period ? `за ${period}` : "за все доступное проверенное окно"; } function strongestIncomingYear(overview) { const years = Array.isArray(overview.yearly_breakdown) ? overview.yearly_breakdown : []; const sorted = years .map((item) => toRecordObject(item)) .filter((item) => { if (!item) { return false; } return Number(item.incoming_total_amount) > 0; }) .sort((left, right) => { const amountDelta = Number(right.incoming_total_amount) - Number(left.incoming_total_amount); if (amountDelta !== 0) { return amountDelta; } return String(left.year_bucket ?? "").localeCompare(String(right.year_bucket ?? "")); }); return sorted[0] ?? null; } function strongestNetYear(overview) { const years = Array.isArray(overview.yearly_breakdown) ? overview.yearly_breakdown : []; const sorted = years .map((item) => toRecordObject(item)) .filter((item) => { if (!item) { return false; } return Number(item.net_amount) !== 0; }) .sort((left, right) => { const amountDelta = Number(right.net_amount) - Number(left.net_amount); if (amountDelta !== 0) { return amountDelta; } return String(left.year_bucket ?? "").localeCompare(String(right.year_bucket ?? "")); }); return sorted[0] ?? null; } function businessOverviewCoverageLimitLine(overview) { const incoming = toRecordObject(overview.incoming_customer_revenue); const outgoing = toRecordObject(overview.outgoing_supplier_payout); const limited = []; if (incoming?.coverage_limited_by_probe_limit === true) { limited.push("входящие"); } if (outgoing?.coverage_limited_by_probe_limit === true) { limited.push("исходящие"); } return limited.length > 0 ? `Важно: ${limited.join(" и ")} уперлись в лимит выборки MCP, поэтому это проверенный срез найденных строк, а не гарантированно полный бухгалтерский оборот.` : null; } function businessOverviewYearRowsLine(overview) { const years = Array.isArray(overview.yearly_breakdown) ? overview.yearly_breakdown : []; const values = years .map((item) => toRecordObject(item)) .filter((item) => Boolean(item)) .slice(0, 6) .map((item) => { const year = toNonEmptyString(item.year_bucket); const incoming = moneyText(item.incoming_total_amount_human_ru); const net = moneyText(item.net_amount_human_ru); const direction = item.net_direction === "net_outgoing" ? "нетто в минус" : "нетто в плюс"; return year && incoming && net ? `${year}: входящие ${incoming}, ${direction} ${net}` : null; }) .filter((item) => Boolean(item)); const joined = values.join("; "); return values.length > 0 ? `По годам: ${sentenceAmount(joined) ?? joined}.` : null; } function buildCompactBusinessOverviewReply(entryPoint, draft) { const turnInput = toRecordObject(entryPoint.turn_input); const graph = toRecordObject(turnInput?.data_need_graph); const bridge = toRecordObject(entryPoint.bridge); const pilot = toRecordObject(bridge?.pilot); const overview = toRecordObject(pilot?.derived_business_overview); const graphReasons = readStringArray(graph?.reason_codes); const isBusinessOverview = toNonEmptyString(graph?.business_fact_family) === "business_overview" || toNonEmptyString(pilot?.pilot_scope) === "business_overview_route_template_v1"; const rankingNeed = toNonEmptyString(graph?.ranking_need); const directMoneyAnswer = graphReasons.includes("data_need_graph_business_overview_direct_money_answer"); if (!isBusinessOverview || !overview || (!rankingNeed && !directMoneyAnswer)) { return null; } const incoming = toRecordObject(overview.incoming_customer_revenue); const outgoing = toRecordObject(overview.outgoing_supplier_payout); const incomingAmount = moneyText(incoming?.total_amount_human_ru); const outgoingAmount = moneyText(outgoing?.total_amount_human_ru); const netAmount = moneyText(overview.net_amount_human_ru); const netDirection = overview.net_direction === "net_outgoing" ? "операционное нетто в минус" : "расчетное операционное нетто"; const period = businessOverviewPeriodText(overview); const limitLine = businessOverviewCoverageLimitLine(overview); const lines = []; if (rankingNeed) { const incomingLeader = strongestIncomingYear(overview); const netLeader = strongestNetYear(overview); const leaderYear = toNonEmptyString(incomingLeader?.year_bucket); const leaderAmount = moneyText(incomingLeader?.incoming_total_amount_human_ru); const leaderRows = Number(incomingLeader?.incoming_rows_with_amount); if (!leaderYear || !leaderAmount) { return null; } lines.push(`Коротко: самый доходный год в доступном денежном контуре 1С — ${leaderYear}: ${leaderAmount}${Number.isFinite(leaderRows) && leaderRows > 0 ? ` по ${leaderRows} строкам с суммой` : ""}.`); const netYear = toNonEmptyString(netLeader?.year_bucket); const netYearAmount = moneyText(netLeader?.net_amount_human_ru); if (netYear && netYearAmount) { const netLabel = netLeader?.net_direction === "net_outgoing" ? "нетто в минус" : "нетто в плюс"; lines.push(`По расчетному операционному нетто лучший год: ${netYear}, ${netLabel} ${sentenceAmount(netYearAmount) ?? netYearAmount}.`); } lines.push('Метод: "доходный" здесь трактую как подтвержденные входящие поступления/выручку по найденным строкам 1С, не как чистую бухгалтерскую прибыль.'); if (incomingAmount && outgoingAmount && netAmount) { lines.push(`Сверка по окну: входящие ${incomingAmount}, исходящие ${outgoingAmount}, ${netDirection} ${sentenceAmount(netAmount) ?? netAmount}.`); } const yearRows = businessOverviewYearRowsLine(overview); if (yearRows) { lines.push(yearRows); } } else if (incomingAmount || outgoingAmount || netAmount) { lines.push(`Коротко: ${period} по подтвержденным строкам 1С получили ${incomingAmount ?? "0 руб."}; исходящие платежи/списания ${outgoingAmount ?? "0 руб."}; ${netDirection} ${sentenceAmount(netAmount) ?? netAmount ?? "0 руб"}.`); lines.push('Метод: "заработали" здесь считаю как денежный operating-flow proxy по 1С; это не чистая прибыль и не финрезультат.'); const topCustomer = toRecordObject(Array.isArray(overview.top_customers) ? overview.top_customers[0] : null); const customerName = toNonEmptyString(topCustomer?.axis_value); const customerAmount = moneyText(topCustomer?.total_amount_human_ru); if (customerName && customerAmount) { lines.push(`Крупнейший подтвержденный источник входящих денег в этом срезе: ${customerName} — ${sentenceAmount(customerAmount) ?? customerAmount}.`); } } else { return null; } if (limitLine) { lines.push(limitLine); } lines.push("Для ответа именно про чистую прибыль нужно отдельно считать себестоимость, расходы и закрытие периода."); const reply = lines.join("\n").trim(); return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null; } function statusFrom(entryPoint) { if (!entryPoint || entryPoint.entry_status === "skipped_not_applicable") { return "not_applicable"; } if (entryPoint.entry_status === "skipped_needs_more_context") { return "clarification_candidate"; } const bridgeStatus = toNonEmptyString(toRecordObject(entryPoint.bridge)?.bridge_status); if (bridgeStatus === "answer_draft_ready") { return "ready_for_guarded_use"; } if (bridgeStatus === "needs_clarification") { return "clarification_candidate"; } if (bridgeStatus === "checked_sources_only") { return "checked_sources_only_candidate"; } if (bridgeStatus === "blocked") { return "blocked"; } if (bridgeStatus === "unsupported") { return "unsupported"; } return "not_applicable"; } function replyTypeFor(status) { if (status === "clarification_candidate") { return "clarification_required"; } if (status === "blocked" || status === "unsupported" || status === "not_applicable") { return "no_grounded_answer"; } return "partial_coverage"; } function buildReplyText(entryPoint, status) { const bridge = toRecordObject(entryPoint.bridge); const draft = toRecordObject(bridge?.answer_draft); if (!draft) { if (status === "clarification_candidate") { return "Нужно уточнить контекст перед поиском в 1С: контрагента, период или организацию."; } return null; } const compactBusinessOverviewReply = buildCompactBusinessOverviewReply(entryPoint, draft); if (compactBusinessOverviewReply) { return compactBusinessOverviewReply; } const blocks = [ toNonEmptyString(draft.headline) ? `Коротко: ${localizeLine(String(draft.headline))}` : null, section("Что подтверждено:", toStringList(draft.confirmed_lines)), section("Что можно сказать только как вывод:", toStringList(draft.inference_lines)), section("Что не подтверждено:", toStringList(draft.unknown_lines)), section("Ограничения проверки:", toStringList(draft.limitation_lines)), toNonEmptyString(draft.next_step_line) ? `Следующий шаг: ${localizeLine(String(draft.next_step_line))}` : null ].filter((item) => Boolean(item)); const reply = blocks.join("\n\n").trim(); return reply.length > 0 && !hasInternalMechanics(reply) ? reply : null; } function buildAssistantMcpDiscoveryResponseCandidate(entryPoint) { const entry = entryPoint ?? null; const status = statusFrom(entry); const reasonCodes = uniqueStrings(entry?.reason_codes ?? []); pushReason(reasonCodes, `mcp_discovery_response_candidate_${status}`); pushReason(reasonCodes, "mcp_discovery_response_candidate_not_hot_wired"); const replyText = entry && (status === "ready_for_guarded_use" || status === "checked_sources_only_candidate" || status === "clarification_candidate") ? buildReplyText(entry, status) : null; return { schema_version: exports.ASSISTANT_MCP_DISCOVERY_RESPONSE_CANDIDATE_SCHEMA_VERSION, policy_owner: "assistantMcpDiscoveryResponseCandidate", candidate_status: replyText ? status : status === "clarification_candidate" ? status : status, hot_runtime_wired: false, reply_type: replyTypeFor(status), reply_text: replyText, eligible_for_future_hot_runtime: Boolean(replyText) && (status === "ready_for_guarded_use" || status === "checked_sources_only_candidate" || status === "clarification_candidate"), must_keep_internal_mechanics_hidden: true, reason_codes: reasonCodes }; }