Возможности Wiki
Wiki упорядочивает материалы базы знаний в связанные друг с другом Markdown-страницы. После приёма документов модель извлекает такие сущности, как персоны, продукты и концепции, и генерирует страницы со ссылками на источники, что упрощает просмотр по темам.
Пользователи могут напрямую редактировать сгенерированные страницы, просматривать историю версий и откатывать их. Агент также может читать и поддерживать страницы через инструменты Wiki; область доступа по-прежнему определяется правами базы знаний.
Включение и просмотр Wiki
- Откройте базу знаний → включите Wiki в разделе «Стратегия индексации»;
- Загрузите документы (уже имеющиеся документы тоже будут включены, повторно загружать не нужно);
- Дождитесь генерации. Генерация Wiki выполняется асинхронно и при большом числе документов занимает время; в «хлебных крошках» базы знаний появляется подсказка «Индексируется»;
- По завершении откройте вкладку Wiki базы знаний для просмотра; на вкладке Граф видны связи между страницами.
Генерация Wiki увеличивает количество вызовов модели; объём зависит от размера документов и плотности извлечения. В конфигурации Wiki базы знаний можно выбрать focused, standard или exhaustive; подробности см. в разделе Гранулярность извлечения.
Просмотр графа Wiki
Граф организован группами по связанным страницам и показывает поясняющие темы, объединяющие содержимое группы. Узлы и заголовки не перекрываются, что упрощает поиск интересующего элемента в общей сети связей.
- По клику на тему группы можно сфокусироваться на этих страницах, переключаться между другими группами с помощью меню групп и выходить из фокуса кнопкой «Вернуться к полному графу» или Esc.
- Страницы без связей можно скрывать; для поиска нужной страницы доступны поиск и фильтр по типам страниц.
- По клику на узел открывается страница, а по линиям — связанные страницы; страницы также соединены с сводными страницами документов-источников, что упрощает отслеживание материалов.
Эта страница показывает связи между страницами Wiki и отличается от графа знаний, который извлекает сущности и связи в настройках базы знаний.
Редактирование и откат страниц
После редактирования текста на странице Wiki можно просмотреть историю версий и сравнить изменения. История различает источники: автоматическая генерация, агент, ручное редактирование и откат. Откат создаёт новую версию на основе выбранного исторического содержимого, а номер версии продолжает увеличиваться.
Система в первую очередь удаляет старые автоматически сгенерированные версии: после достижения 50 исторических версий удаляются усекаемые снимки, а при достижении 200 удаляются все источники по жёсткому пределу. Содержимое, которое нужно хранить долго, следует архивировать отдельно. Версии, записанные до обновления, или уже удалённые версии не имеют снимков: при выборе такой версии панель истории показывает предупреждение вместо различий; при отсутствии базовой линии для сравнения сразу отображается полный текст выбранной версии. Сравнение и откат остальных версий не затрагиваются.
Просмотр изменений и состояния генерации
Записи операций создания, обновления, удаления и пакетной генерации страниц отображаются в разделе «База знаний → Настройки → Активность». Во время обработки документов можно проверить состояние индексации; после перезапуска сервиса система восстанавливает сохранённые ожидающие задачи Wiki. При удалении базы знаний её страницы Wiki, каталоги, проблемы и история версий также очищаются. Совместимость интерфейсов и механизмы восстановления см. в справочном разделе.
Справочник по версиям и работе
Ручное редактирование и история версий
Страницы Wiki поддерживают ручное редактирование и откат версий: пользователи могут исправлять сгенерированное содержимое и просматривать источник, автора и время каждой версии. Записи версий введены миграцией 000075.
Источник версии и автор
В wiki_pages есть два поля происхождения; last_edit_source помечает тип автора текущей версии:
edit_source | Значение |
|---|---|
pipeline | записано конвейером генерации Wiki (в унаследованных строках пустая строка трактуется как pipeline) |
agent | записано Agent через инструменты wiki_write_page / wiki_replace_text и т. п. |
user | изменено вручную в редакторе |
revert | версия, созданная откатом |
Сопутствующее поле last_editor_id фиксирует автора (пусто при записи фоновым конвейером). Интерфейс на основе этого показывает источник редактирования каждой версии.
Снимки и откат
- Перед каждым перезаписыванием страницы старая версия целиком сохраняется в снимок в
wiki_page_revisions(заголовок, текст, аннотация, тип страницы, состояние, псевдонимы, а также автор и время версии); текущая версия существует только вwiki_pages. Уникальный индекс по(page_id, version)вместе сON CONFLICT DO NOTHINGделает путь записи «сначала снимок, потом обновление» идемпотентным при повторных попытках; GET /revisions/*slugвозвращает список исторических версий (в обратном порядке, без текста, с текущим номером версии); с?version=Nвозвращается полный текст этой версии для diff;POST /revertпринимает{slug, version}для отката. Откат создаёт новую версию на основе содержимого целевой версии, номер версии продолжает увеличиваться, аedit_sourceпомечается какrevert, поэтому сам откат тоже можно откатить. Откат к текущей версии возвращает 400 (обычно это значит, что фронтенд использует устаревший список истории).
Политика хранения истории
История версий очищается по двум уровням пределов (internal/types/wiki_page.go):
- Мягкий предел 50 версий: удаляются только «усекаемые» снимки, то есть записанные
pipelineи унаследованные пустые источники; - Жёсткий предел 200 версий: усекаются все независимо от автора, что гарантирует ограниченность хранилища даже для страниц, поддерживаемых исключительно вручную.
До достижения жёсткого предела система в первую очередь очищает автоматически сгенерированную историю, сохраняя записи ручного редактирования.
История операций (поток активности базы знаний)
Раньше Wiki вела отдельный журнал операций (таблица wiki_log_entries + эндпоинт GET /wiki/log + вкладка журнала в WikiBrowser). Эта лента дублировала поток активности базы знаний, поэтому была полностью удалена миграцией 000077_remove_wiki_log: таблица была удалена через DROP, унаследованные страницы с page_type = 'log' также удалены, а log больше не является допустимым типом страницы.
Теперь поток активности базы знаний — единственный источник истории операций:
- по завершении пакета ingest
wiki_ingest_batch.goсуммирует число действий каждого типа в пакете и вызываетservice.RecordWikiContentActivity(), записывая активностьwiki_content_changed; - при ручном создании/обновлении/удалении страницы в WikiBrowser
internal/handler/wiki_page.goтак же проецируетmanual_create/manual_update/manual_deleteв поток активности; - записи активности попадают в систему журналов аудита (
kb_activity.go→AuditLogService), их можно просмотреть в разделе «База знаний → Настройки → Активность», а политика хранения совпадает с другими журналами аудита (см. Наблюдаемость и аудит); - запись выполняется best-effort: сбой записи активности не приводит к сбою самого редактирования wiki.
Замечание по обновлению: если внешние интеграции по-прежнему вызывают GET /api/v1/knowledgebase/:kb_id/wiki/log, нужно перейти на интерфейс потока активности базы знаний GET /api/v1/knowledge-bases/:id/activity.
Восстановление после сбоев
internal/container/recover_pending_wiki_tasks.go при запуске сервиса закрывает пробелы, оставленные режимом Lite (внутрипроцессный SyncTaskExecutor) или прерыванием постановки в очередь Redis:
- Сканирует в сохранённой таблице
task_pending_opsожидающие комбинации сscope = knowledge_baseиtask_type ∈ {wiki:ingest, wiki:finalize}; - Удаляет остаточные строки для удалённых KB или тенантов (fail-closed);
- Для каждой активной KB повторно ставит в очередь задачи-триггеры:
wiki:ingestбез TaskID (допускается параллельность нескольких пакетов),wiki:finalizeс дедупликацией по"wiki-finalize-" + KB_ID(для одной KB остаётся только один finalize). Повторная постановка безвредна — ingest разбирает непересекающиеся строки, а finalize объединяются внутри lane.
Прочая защита во время работы:
- Тенант удалён: задачи ingest / finalize перед вызовом модели проверяют, жив ли тенант; если тенант удалён, очередь этой базы знаний отбрасывается и запросы к модели больше не создаются;
- Wiki не может работать: если при срабатывании выясняется, что в базе знаний выключен Wiki, отсутствует модель синтеза или модель удалена, неразобранные операции ingest очищаются, а соответствующие документы освобождаются — документы не застревают в состоянии «Индексируется»;
- Потеря задачи-триггера: базы знаний, у которых есть только сохранённые операции, но нет задач-триггеров, повторно запускаются фоновым обходом, не чаще одного раза на пороговый период обхода для каждой базы знаний;
- Повтор при временных ошибках: при вызове модели в случае 408/429/5xx, таймаута, сброса соединения или 403 с признаками ограничения частоты (например «превышена частота вызовов»,
rate limit) повтор выполняется с экспоненциальной задержкой; 403, связанные с авторизацией, не повторяются; - Приоритет по числу сбоев: при разборе ожидающих документов в первую очередь обрабатываются документы с меньшим числом сбоев, чтобы постоянно сбоящие документы не блокировали новые.
Справочник по страницам и интерфейсам
Модель страниц и иерархия
Типы страниц (PageType)
internal/types/wiki_page.go определяет 6 типов страниц:
| Тип | Описание |
|---|---|
summary | страница аннотации одного исходного документа (slug вида summary/<knowledge-uuid>) |
entity | страница сущности (персоны, организации, продукты, технологии и т. п.) |
concept | страница концепции/темы |
index | страница индекса уровня wiki (метаданные) |
synthesis | страница комплексного анализа, создаётся только Agent через инструмент wiki_write_page |
comparison | страница сравнения, создаётся только Agent через инструмент wiki_write_page |
Состояния страницы (WikiPageStatus): draft / published (по умолчанию) / archived.
Дерево каталогов (Folder Hierarchy)
Миграция 000061_wiki_page_hierarchy.up.sql вводит отдельную таблицу wiki_folders (модель списка смежности):
WikiFolderорганизует дерево черезParentID(пустая строка означает корень) + материализованныйPath(цепочка имён, соединённая/); пустые папки могут существовать самостоятельно, пользователь может сначала построить каркас;WikiPage.FolderID— единственный источник истины о принадлежности страницы (FK →wiki_folders.id, пустая строка означает корень wiki);CategoryPath/WikiPath/Depth/SortOrderна странице — это кешированная проекция, производная от цепочки folder;- генерируемый моделью путь категории имеет глубину не более 3 уровней (константа
WikiCategoryMaxDepth = 3), аCleanWikiCategoryPath()нормализует полноширинные разделители (/,|→/) и удаляет метки типов, такие как «сущность», «концепция»; - когда страница помещается в созданную пользователем папку, путь папки используется как путь категории без изменений; папки с именами «концепция», «Concepts» и т. п. не отбрасываются как метки типа.
Ключевые поля
Slug: уникальный идентификатор страницы внутри KB (см. следующий раздел);SourceRefs: ссылки на источники в формате"<knowledge_id>|<doc_title>";ChunkRefs: ссылки на доказательства на уровне блоков;InLinks/OutLinks: обратные/прямые ссылки wiki-link, поддерживают структуру графа;GET /graphпозволяет запрашивать глобальное представление или ego-вид;Aliases: псевдонимы (используются для поиска и указания старых имён после объединения при дедупликации);Version: номер версии.
Публикация и доступ
Все маршруты Wiki находятся под /api/v1/knowledgebase/:kb_id/wiki (internal/router/routes_knowledge.go), публичного режима доступа без входа нет, чтение и запись подчиняются RBAC и контролю доступа KB:
Интерфейсы чтения (Viewer + KBAccessRead)
| Метод | Путь | Описание |
|---|---|---|
| GET | /pages | Список страниц |
| GET | /pages/*slug | Получить одну страницу по slug |
| GET | /folders | Дерево каталогов |
| GET | /index | Страница индекса |
| GET | /graph | Граф ссылок (глобальный обзор / ego-режим) |
| GET | /stats | Статистика |
| GET | /search?q=... | Поиск |
| GET | /lint / /issues | Результаты проверки качества / список проблем |
| GET | /revisions/*slug | Список истории версий; с ?version=N — полный текст этой версии |
KBAccessRead охватывает: владельца KB, общий доступ в организации и доступ, полученный через общий Agent.
Интерфейсы записи (OwnedWikiKBOrAdmin + KBAccessWrite)
| Метод | Путь | Описание |
|---|---|---|
| POST / PUT / DELETE | /pages, /pages/*slug | Создание / обновление / удаление страницы |
| POST / PUT / DELETE | /folders, /folders/:folder_id | Управление каталогами |
| PUT | /move-page | Переместить страницу в каталог |
| POST | /rebuild-links | Перестроить граф ссылок |
| POST | /auto-fix | Запустить автоматическое исправление |
| PUT | /issues/:issue_id/status | Обновить состояние проблемы |
| POST | /revert | Откат к указанной версии (body: {slug, version}) |
Права на запись определяются принадлежностью KB: участнику достаточно владеть этой KB, чтобы управлять её wiki, иначе 403. Для API Key используется сопоставление по возможностям ingest / retrieve.
Просмотр на фронтенде обеспечивает WikiBrowser.vue; во время разбора документов wikiStatusRefresh.ts опрашивает parse_status (pending / processing / finalizing) и продолжает опрос, если разбор завершён, а аннотации ещё генерируются. Состояние раскрытия дерева каталогов поддерживается отдельно в wikiDirectoryState.ts: после создания папки или обновления данных expandWikiDirectoryPath() помечает все уровни каталогов на текущем пути как «раскрытые пользователем», чтобы при обновлении всё дерево не схлопывалось обратно в состояние по умолчанию.
Связь с Agent
Агент может читать, изменять страницы и обрабатывать проблемы через следующие 9 инструментов Wiki (для повторного чтения исходных документов используется общий read_document); определения инструментов находятся в internal/agent/tools/definitions.go:
| Инструмент | Назначение | Ключевые параметры |
|---|---|---|
wiki_read_page | Пакетно читать полный текст страниц по slug | slugs: string[] |
wiki_search | Поиск страниц (заголовок / slug / псевдоним / аннотация / содержимое; query интерпретируется как регистронезависимое POSIX-регулярное выражение; текст, не являющийся корректным регулярным выражением, например C++, сопоставляется буквально; regex=false принудительно включает буквальное сопоставление) | query, regex?, knowledge_base_ids?, limit? (старые параметры queries, knowledge_base_id по-прежнему принимаются) |
wiki_write_page | Создание/перезапись всей страницы (synthesis, comparison можно создать только так) | slug, title, summary, content, page_type, aliases?, source_refs? |
wiki_replace_text | Точная замена текста внутри страницы | slug, old_text, new_text |
wiki_rename_page | Переименовать slug с автоматическим обновлением обратных ссылок | slug, new_slug |
wiki_delete_page | Удалить страницу и очистить битые ссылки | slug |
read_document | Повторно прочитать исходный документ: заголовок метаданных + блоки, можно постранично или с query для поиска внутри документа (заменяет прежний wiki_read_source_doc; доступен и для KB только с Wiki, так как блоки всегда сохраняются в БД) | id (dN / cN), offset?, limit?, query?, regex?, context? |
wiki_flag_issue | Пометить проблему страницы | slug, issue_type ∈ {mixed_entities, contradictory_facts, out_of_date, other}, description |
wiki_read_issue | Просмотреть детали проблемы | ID проблемы |
wiki_update_issue | Обновить состояние проблемы | ID проблемы, status ∈ {pending, ignored, resolved} |
Рекомендуемый порядок чтения — wiki_search → wiki_read_page → read_document: сначала найти страницу, затем прочитать её целиком, а при необходимости точной ссылки вернуться к блокам cN исходного источника. Вывод инструментов имеет XML-подобную структуру (<wiki_page><metadata>...<summary>...<content>...), фронтенд разбирает её с помощью parseWikiToolReferences() из frontend/src/utils/wikiToolReferences.ts и отрисовывает карточки ссылок в диалоге.
Сопутствующие механизмы:
- Wiki Scope: в рамках сессии Agent поддерживается белый список wiki-KB, поддерживается сужение области до конкретных документов/тегов через
@mention, а при выполнении инструментов автоматически фильтруютсяsource_refs(internal/agent/tools/wiki_tools.go); - Права на запись: области поиска достаточно прав на чтение, тогда как инструменты изменения (
wiki_write_page,wiki_replace_text,wiki_rename_page,wiki_delete_page,wiki_flag_issue,wiki_update_issue) действуют только на редактируемые вызывающим базы знаний, то есть базы знаний текущего пространства или базы знаний, к которым получены права editor и выше через общий доступ организации. Сам вызывающий тоже должен иметь права на запись: роль в пространстве Contributor и выше; ограниченному API key требуется возможностьingest. Работающие от имени Viewer IM, веб-встраивание и эндпоинты MCP поэтому только для чтения. Если в области нет редактируемой базы знаний wiki, эти инструменты не регистрируются. Общий агент всегда только для чтения; - Wiki Fixer: встроенный Agent (
types.BuiltinWikiFixerID), отвечает за автоматическое исправление проблем wiki (битые ссылки, путаница сущностей и т. п.). При кросс-тенантном доступе к общей KB требуется роль в тенанте ≥ Editor и выполняется автоматическое повышение до контекста тенанта-источника (internal/handler/session/wiki_fixer_scope.go). После повышения используются встроенные конфигурации по умолчанию, только для этой одной KB, не включаются MCP, навыки, песочница и веб-поиск, модель откатывается к собственной модели этой KB, а пользовательские настройки fixer от вызывающего не попадают в пространство-источник; - Замкнутый цикл проблем: таблица
wiki_page_issues+ интерфейс lint +auto-fix; и люди, и Agent могут сообщать о проблемах и обрабатывать их.
Процесс генерации
Генерация Wiki запускается приёмом документов (knowledge ingest) и выполняется асинхронно через очередь задач Redis. Типы задач определены в internal/types/task.go:
TypeWikiIngest = "wiki:ingest"
TypeWikiFinalize = "wiki:finalize"Весь конвейер состоит из четырёх этапов (структура Map-Reduce):
| Этап | Задача | Что делает | Промпт LLM (internal/agent/prompts_wiki.go) |
|---|---|---|---|
| Pass 0: извлечение кандидатов | wiki:ingest | Извлекает из документов каркас slug-кандидатов (JSON из entities + concepts) | WikiCandidateSlugPrompt |
| Pass 1..N: цитирование по блокам | wiki:ingest | Для каждого chunk помечает ссылками slug-кандидатов, выводит { citations: {"slug": ["c001", ...]}, new_slugs: [...] }; для длинных префиксов используется prefix caching | WikiChunkCitationPrompt |
| Reduce: объединение страниц | wiki:ingest | Инкрементально обновляет или объединяет страницы по slug, выводит SUMMARY: ... + текст Markdown; строгая привязка к источникам, запрет галлюцинаций, дедупликация, запрет самоссылок | WikiPageModifySystemPrompt + WikiPageModifyUserPrompt |
| Finalize: завершение | wiki:finalize | Перестраивает страницы индекса, чистит битые ссылки, добавляет перекрёстные ссылки, подрезает каталоги — чистый SQL/алгоритмы на графе, без вызова LLM | — |
Вспомогательные промпты:
WikiTaxonomyPlanPrompt: единообразно планирует пути каталогов для всех сущностей/концепций одного пакета (не более 2 уровней, с приоритетом повторного использования существующих папок), обеспечивая связность дерева каталогов;WikiDeduplicationPrompt: определяет, указывает ли новый извлечённый элемент на тот же объект, что и существующая страница; ключевой принцип — "related ≠ same" (связанное не значит одинаковое), возвращает{ merges: { "entity/new": "entity/existing" } }. Имена и псевдонимы сравниваются в обе стороны (имя с псевдонимом, псевдоним с псевдонимом), но общего псевдонима или сокращения самого по себе недостаточно, чтобы считать объекты одним и тем же.
Прочие правила дедупликации и записи:
- Повторное использование имени между типами: при повторном разборе модель может сначала отнести один и тот же объект к
concept/X, а затем кentity/X. При отсутствии страницы того же типа страница другого типа с совпадающим нормализованным заголовком обновляется напрямую, а не создаётся страница-двойник; - Ссылки на изображения с описанием: на этапе Reduce при чтении процитированных блоков подпись изображения / текст OCR встраиваются прямо в содержимое блока, чтобы модель могла оценить, относится ли изображение к странице;
- Усечение при перезаписи всей страницы: если перезапись всей страницы обрывается из-за предела длины вывода, выполняется не более 3 дополнительных раундов с бесшовной склейкой; если текст так и не дописан, запись отменяется и фиксируется предупреждение, а неполный текст не записывается на страницу;
- Отдельный иероглиф не связывается автоматически: страница с заголовком из одного иероглифа может существовать, но ссылка на неё автоматически не добавляется в текст других страниц, чтобы избежать ошибочных ссылок в словах вроде «ветер-песок» или «ядро».
Гранулярность извлечения
WikiExtractionGranularity в WikiConfig (хранится в столбце JSONB knowledge_bases.wiki_config) управляет плотностью извлечения:
| Гранулярность | Поведение |
|---|---|
focused | Только 3-7 основных тем |
standard (по умолчанию) | Темы + сущности/концепции, которые содержательно обсуждаются (абзац/несколько упоминаний/более 2-3 предложений) |
exhaustive | Исчерпывающе все именованные объекты и общепризнанные концепции |
Параллелизм и пакетная обработка
Параметры, связанные с WikiConfig (internal/types/wiki_page.go):
| Параметр | По умолчанию | Описание |
|---|---|---|
IngestBatchSize | 5 | Число ожидающих документов, разбираемых за один пакет |
IngestMapParallel | 10 | Число параллельных задач errgroup на этапе Map (извлечение+цитирование по каждому документу) |
IngestReduceParallel | 10 | Число параллельных задач на этапе Reduce (запись страницы по каждому slug) |
IngestMaxInflight | 4 | Максимум параллельных пакетов для одной KB (обеспечивает справедливость между KB) |
На этапе планирования каталогов при вычислении эмбеддингов папок и страниц запросы, как и другие вызовы эмбеддингов, разбиваются по BATCH_EMBED_SIZE, поэтому служба модели не отклоняет их из-за слишком большого одиночного ввода.
Диаграмма процесса генерации
Механизм Slug
- Формат:
<type>/<name>, напримерentity/acme-corp,concept/rag,summary/<knowledge-uuid>; в нижнем регистре, разделяется дефисами, нелатинские имена транслитерируются/пиньинизируются; - Уникальность: уникальный индекс БД (
000037_wiki_and_indexing.up.sql):
CREATE UNIQUE INDEX idx_kb_slug ON wiki_pages (knowledge_base_id, slug) WHERE deleted_at IS NULLто есть slug уникален в пределах одной базы знаний и может повторяться между KB;
- Стабильность: при повторном извлечении после обновления документа промпт заставляет модель повторно использовать старый slug —
If an entity or concept from the previous extraction still exists in the current document, reuse its exact slug from the previous list. Do NOT generate a new slug for the same thing.
Новый slug создаётся только для впервые появившихся объектов, а исчезнувшие элементы больше не выводятся;
- Slug Handle (прокси-дескриптор): в вызовах LLM при ingest настоящие slug с высокой энтропией (особенно
summary/...с UUID) заменяются короткими дескрипторами (ref-1,ref-2), а после того как модель выводит[[ref-1|title]], бэкенд восстанавливает настоящий slug, чтобы модель не перепутала UUID (internal/application/service/wiki_slug_handles.go); - Роль ссылок: ссылки wiki в ответах Agent имеют вид
[[slug|title]], аInLinks/OutLinksподдерживают граф страниц по slug; переименование slug (инструментwiki_rename_page) автоматически обновляет все обратные ссылки.
Справочник по реализации
Все пути ниже указаны относительно корня репозитория:
| Слой | Файл |
|---|---|
| Структуры данных | internal/types/wiki_page.go |
| HTTP Handler | internal/handler/wiki_page.go |
| Конвейер генерации | internal/application/service/wiki_ingest.go, wiki_ingest_batch.go, wiki_ingest_cite.go, wiki_ingest_dedup.go, wiki_ingest_taxonomy.go |
| Сервис страниц | internal/application/service/wiki_page.go, wiki_linkify.go, wiki_lint.go, wiki_slug_handles.go |
| Промпты LLM | internal/agent/prompts_wiki.go |
| Инструменты Agent | internal/agent/tools/wiki_*.go (регистрируются в internal/agent/tools/definitions.go) |
| Восстановление после сбоев | internal/container/recover_pending_wiki_tasks.go |
| Маршруты | RegisterWikiPageRoutes из internal/router/routes_knowledge.go (тесты поведения: internal/router/router_wiki_test.go) |
| Миграции БД | migrations/versioned/000037_wiki_and_indexing.up.sql, 000061_wiki_page_hierarchy.up.sql, 000077_remove_wiki_log.up.sql |
| Фронтенд | frontend/src/views/knowledge/wiki/WikiBrowser.vue, frontend/src/api/wiki/, frontend/src/utils/wikiToolReferences.ts |
