v1.18.0
Исправлено
- Устойчивость контрактов хелперов («хрупкость контрактов»). Сравнительный e2e-раунд показал, что агент берёт задачи, но «цена» (retry, токены) — это угадывание правдоподобного, но неверного контракта хелпера: жёсткая ошибка либо «тихо пустой» результат. Лечим сами контракты, делая их толерантными (принимают оба варианта) или самокорректирующимися (вместо тихой ошибки — HINT, который агент уже умеет читать). Без изменения поисковых движков, схемы индекса и
BUILDER_VERSION(14) — перестройка боевых индексов НЕ требуется (нормализация только на read/return-слое, build↔update байт-сходимость не затронута).- Толерантность ключей атрибутов (Фикс 1).
get_object_full_structureотдаёт{name, synonym, type}, аfind_attributes—{attr_name, attr_synonym, attr_type}; агент, переносящий паттерн с одного хелпера на другой, писалa['attr_name']на структуре и получал детерминированныйKeyError(6 из 10 e2e-тестов). Новый dict-подкласс_AttrRecordпринимает доступ по «чужому» имени ключа прозрачно (через[],.get,in), но итерация /.keys()/len()/json.dumpsостаются каноничными — агент по-прежнему видит реальные имена и учится, нулевая цена по токенам (алиасы не сериализуются). Применён на всех helper-return-поверхностях обоих хелперов +parse_object_xml(вложенные записиattributes/dimensions/resources+tabular_sections[*].attributes). Алиасинг охватывает только триаду name/synonym/type; служебныйattr_kindалиаса не имеет (намеренно — у структурных записей его нет). Teaching-тексты (slim/full-help, registry-recipe, Sandbox-hint) смягчены с «будет KeyError» на «attr_name — допустимый алиас». paramsстрокой →list[str](Фикс 2). Сигнатура метода вextract_procedures/find_exports/search_methodsвозвращалась строкой →AttributeErrorпри итерации. Новый разборщик_split_params(мини state-machine, устойчивый к удвоенным кавычкам BSL""и строковому default с запятой видаРазделитель = ", "; отбрасывает регистронезависимый по-значению-префиксЗнач/Valи хвост= <default>) применяется на helper-границе (после вызова IndexReader + в live-парсере_parse_procedures) идемпотентно (isinstance str-guard — list-вход не ломается, покрывает duck-typed/fake-ридеры). Build-time и хранение (params TEXT) не тронуты — нормализация только на агент-слое, без reindex. Дополнительно: sandbox-hint про формуparams— если агент по привычке обращается к элементу как кlist[dict](p['name']/p.get('name')) и ловитTypeError: string indices must be integers/AttributeError: 'str' object has no attribute …,_add_error_hintsподсказывает, что элемент уже строка-имя (for name in m['params']), — самокоррекция вместо повторного угадывания.find_callers_context— самокоррекция вместо тихой пустоты (Фикс 3). (1)module_hint=int(агент сдвинул позиционные аргументы) больше не роняетAttributeErrorвнутри_normalize_module_hint(hint.strip()) — коэрсится в''+_meta.arg_warningс явной сигнатуройfind_callers_context(proc_name, module_hint, offset, limit); int-guard стоит ДО вызова ридера. (2)offset >= total(страница пуста, но вызывающие есть —total=6, returned=0) больше не выглядит как «нет вызовов»:_meta.hintсообщает о вероятно перепутанных позиционных аргументах. Guard симметричен для индексного (total_callers) и FS-fallback (total_files) путей; в индексном — ранним возвратом ДО authoritative-ветки и FS-fallback (которые перетёрли бы_meta). Поисковый механизм (get_callers, FS-scan) не изменён.git_searchпустой паттерн (Фикс 4a). Пустой/пробельныйpatternуходил в git-движок и возвращал невнятную таймаут-заглушку → теперь ранний[{"error": "empty pattern", "hint": ...}](list-форма, как любой результатgit_search, а не голый dict).- HINT путей по формату дампа (Фикс 4b).
_resolve_object_xmlгадал.mdovsExt/*.xml→FileNotFoundErrorна CF. Теперь порядок XML-кандидатов и текст HINT ведутся фактическим форматом дампа (format_info.primary_format: CF →Ext/*.xmlпервым, EDT →*.mdoпервым). Кандидаты переупорядочиваются, не сокращаются — все по-прежнему пробуются, корректность на смешанных CF+EDT-расширениях сохраняется.format_infoуже прокинут вmake_bsl_helpers— новых проводок не потребовалось.
- Толерантность ключей атрибутов (Фикс 1).
Тесты
- Новый файл
tests/test_v1_18_0.py(32 теста):_AttrRecord(оба диалекта через[]/.get/in, каноничные.keys()/json,isinstance dict, KeyError без алиаса) + интеграция обоих хелперов (index/live/parse_object_xml, включая ТЧ-колонки);_split_params(много/ноль/Знач+ЗНАЧ+Valcase-insensitive/= default/строка с запятой/удвоенные кавычки/многострочная сигнатура/имя наЗнач…) + идемпотентность на границе и stub-ридере;find_callers_context(offset-overshoot индекс+FS,module_hint=intбез падения);git_searchпустой паттерн →[{error,hint}]; format-aware HINT (CF/EDT ведут своим форматом) + порядок кандидатов на CF-дампе.
Проверено-неактуально
- «Фолбэк при недоступности classifier» (Фикс 5) — НЕ реализуем. Поиск объектов 100% детерминирован (
search_objects/search_methods→ SQLite + Python-ранжирование с live-scan фолбэком);llm_query— явный опциональный хелпер, на пути поиска LLM нет. Сообщение «недоступность classifier» из e2e — слой re-ranking внешнего тест-агента, не наш код; наш сервер оба раза вернул корректный результат, фолбэк уже есть — добавлять нечему. - CF-aware HINT на
glob_files(Фикс 4c) — вне скоупа.glob_filesприходит колбэком из generic-слоя; CF-aware подсказка на его вызов = изменение контракта generic-хелпера, а не дешёвая правка вbsl_helpers.
Совместимость
- Схема индекса и
BUILDER_VERSION(14) не менялись — перестройка боевых индексов не требуется. Все изменения — на runtime/контракт-слое (read/return); семантика результатов (те же объекты/рёбра/тела) сохранена, меняется только их «упаковка». build↔update байт-сходимость не затронута.
Полный список изменений: CHANGELOG.md