DEVELOPMENT.md
DEVELOPMENT.md
Перед началом работы — читать CONSTITUTION.md: инварианты, уровни согласования, цикл разработки, действия при инциденте. Настоящий файл — технический справочник.
Клон brdcastro/maestro rev 81, взятый через интерфейс LM Studio (lms clone brdcastro/maestro).
Аккаунт: rura (проверять: ~/.lmstudio/bin/lms whoami).
Каждый установленный плагин лежит в ~/.lmstudio/extensions/plugins/<owner>/<name>/:
maestro/ ├── manifest.json # {type:"plugin", runner:"node", owner, name, revision} ├── package.json # main: dist/index.js, зависимости ├── .lmsignore # что НЕ публикуется в Hub (src/, node_modules/, tsconfig, *.map) ├── src/index.ts # КОНТРАКТ: экспорт main(pluginContext: PluginContext) ├── dist/ # собранный код (у автора — единственный публикуемый исходник) ├── node_modules/ # ставит инсталлятор LM Studio (node-plugin-installer-v1) └── .lmstudio/ # генерирует сам LM Studio / lms dev — НЕ редактировать ├── entry.ts # бойлерплейт: читает env LMS_PLUGIN_CLIENT_IDENTIFIER / │ # LMS_PLUGIN_CLIENT_PASSKEY / LMS_PLUGIN_BASE_URL, │ # создаёт LMStudioClient, вызывает import("../src/index.ts") │ # → main(pluginContext) → selfRegistrationHost.initCompleted() └── production.js # 0.4.26+: тонкий ESM-лаунчер (~10 КБ), в рантайме # импортирует ../src/index.ts (node 25 исполняет TS); # dist грузится цепочкой импортов. До 0.4.26: esbuild-бандл.
Запуск: процесс LM Studio сам спавнит node ./.lmstudio/production.js
(проверить: lsof -a -p <pid> -d cwd, родитель = LM Studio.app).
Env: LMS_PLUGIN_CLIENT_IDENTIFIER, LMS_PLUGIN_CLIENT_PASSKEY, LMS_PLUGIN_BASE_URL.
Модель рантайма 0.4.26+ (проверено 06.11.2026, инцидент релиза):
.lmstudio/production.js — не самодостаточный бандл, а лаунчер, импортирующий
../src/index.ts в рантайме. Следствия:
src/ обязателен в активной папке — без него плагин падает при старте
(ERR_MODULE_NOT_FOUND .../src/index.ts) и UI показывает «недоступен» (красный);dist/ НЕ требует пере-бандлинга — обновил dist, перезапусти плагин;Возможные хуки PluginContext (регистрация только одного на каждый):
| Хук | Назначение |
|---|---|
withToolsProvider(fn) | список Tool для модели (взаимно исключает PredictionLoopHandler) |
withPromptPreprocessor(fn) | (ctl, userMessage) => string | ChatMessage — обработка перед моделью |
withConfigSchematics(cs) | настройки per-chat (UI: чат → конфигурация плагина) |
withGlobalConfigSchematics(cs) | настройки на всё приложение (API-ключи и т.п.) |
withPredictionLoopHandler(fn) | полный контроль цикла предсказания (не совместим с tools) |
withGenerator(fn) | плагин как генератор |
maestro использует три: ConfigSchematics + ToolsProvider + PromptPreprocessor
(dist/index.js → main()).
| Путь | Роль |
|---|---|
~/ai-projects/LM_Studio/maestro | рабочий клон (здесь). owner=rura, rev 81, git, src/index.ts-шим, node_modules (233MB, скопированы из активного) |
~/.lmstudio/extensions/plugins/brdcastro/maestro | активный установленный экземпляр — именно он обслуживает чаты (процесс node ./.lmstudio/production.js, родитель LM Studio). src/index.ts = шим, добавлен 30.09 |
~/.lmstudio/apps/bionic/extensions/plugins/brdcastro/maestro | копия для приложения Bionic (общие ~/.lmstudio) |
~/lmstudio-plugins/proverennye-iskhodniki/brdcastro__maestro | резервная копия (тоже rev 81, без src) |
~/lmstudio-plugins/karantin/brdcastro__maestro-broken | карантин (сломанная сборка) |
Важно: автор публикует только dist/ (src/ в .lmsignore). TypeScript-исходников
везде нет — разработка ведётся напрямую в dist/*.js (CommonJS, структура 1:1 как у TS,
имена функций не искажены).
Что делает lms dev (проверено):
Типовой итерационный цикл:
Пока работает lms dev, в LM Studio зарегистрированы два maestro:
установленный brdcastro/maestro и dev dev/rura/maestro. Чтобы модель вызывала
инструменты из dev-версии, в UI (Integrations/Плагины) отключите установленный
brdcastro/maestro на время тестов (иначе возможны дубликаты инструментов в промпте
и вызовы «старых»). После тестов: вернуть как было. Проверить состояние визуально —
API/CLI списка плагинов нет.
Критично: убитый dev-сервер = dev-плагин исчез. Если в текущем чате модель уже
вызывала dev-инструменты — перезапустите lms dev перед продолжением, иначе
следующий tool-call упадёт. Установленный brdcastro/maestro от этого не страдает.
Тест-харнесс чистых модулей dist/ — без LM Studio и сети, ноль новых
зависимостей (встроенные node:test + node:assert/strict):
Системного node/npm на машине нет — раннер использует бандл-нод LM Studio
(v25). Переопределение: MAESTRO_NODE=/path/to/node bash test/run.sh.
Покрытие (базовый A2-набор 61 тест; live-харнесс 07.11.2026 — 135 тестов):
| Файл | Модули |
|---|---|
test/core.test.js | errorCodes, outputLimits, shared (validatePath, createSafeToolImplementation), projectMemory, workflowCoordinator, spillToDisk |
test/loopGuard.test.js | loopGuard + denialTracker (module-scoped трекеры: reset в beforeEach) |
test/tfidf.test.js | tokenize + TfIdfIndex |
test/engine.test.js | RetrievalEngine (embedding стабится через require.cache; db — фейк) |
Правила:
Вариант A — горячая замена dist (проверено 06.11.2026 в 0.4.26+; основной способ):
Пере-бандлинга не нужен: лаунчер грузит src→dist в рантайме. Один tool-call в
момент перезапуска может упасть — ожидаемо. Проверка: журнал
~/.maestro-toolbox/logs/tool-calls.jsonl пополняется, contextGauge в
.plugin_state.json.
Вариант B — полный переустан (менялись манифест/зависимости): in-place в 0.4.26 запрещён, только через внешнюю копию:
(инцидент 06.11.2026: шаг с src пропущен → плагин «недоступен»; восстановлено копированием src; полный разбор — в памяти проекта и git log)
Отдельный путь — публикация своего артефакта: lms push (см. ниже) → в LM Studio
установить rura/maestro из Hub. Минус: в системе будут два плагина с одинаковыми
именами инструментов — использовать, только если вариант A не подходит.
Публикация уважает .lmsignore (в Hub уйдёт dist/ без src/, node_modules и карт).
Каждый push = новая revision.
dist/tools/callJournal.js — loopGuard пишет метаданные каждого tool-call (JSONL)
в ~/.maestro-toolbox/logs/tool-calls.jsonl:
ok, error (+code), loop_blocked (+count), streak_blocked (+code), (+code);При инциденте (ст. 10.1) — смотреть хвост журнала перед падением: tail -20 ~/.maestro-toolbox/logs/tool-calls.jsonl (B3: журнал в протокол инцидента).
| Команда | Назначение |
|---|---|
lms clone <owner/name> [path] | скачать артефакт из Hub (owner в manifest переписывается на вас) |
lms dev | dev-сервер в текущей папке (--install — установить вместо сервера; --yes; --no-notify) |
lms push [flags] | загрузить артефакт текущей папки в Hub |
lms login / lms logout / lms whoami | аутентификация |
lms ps, lms server status | диагностика (модели, сервер) |
Инструмент:
Настройки (per-chat):
Типы полей: string, boolean, numeric, select (и scope для группировки).
Чтение значений — через ToolsProviderController / контроллеры (см. dist/tools/* — там
реальные примеры чтения конфига во всех tools maestro).
Свойства ToolCallContext: status(), warn(), signal (AbortSignal — слать в
долгие операции), callId. Ошибки: возвращаемая строка = «попробуй иначе», throw =
авария, warn = мелочь.
Перед началом работы — читать CONSTITUTION.md: инварианты, уровни согласования, цикл разработки, действия при инциденте. Настоящий файл — технический справочник.
Клон brdcastro/maestro rev 81, взятый через интерфейс LM Studio (lms clone brdcastro/maestro).
Аккаунт: rura (проверять: ~/.lmstudio/bin/lms whoami).
Каждый установленный плагин лежит в ~/.lmstudio/extensions/plugins/<owner>/<name>/:
maestro/ ├── manifest.json # {type:"plugin", runner:"node", owner, name, revision} ├── package.json # main: dist/index.js, зависимости ├── .lmsignore # что НЕ публикуется в Hub (src/, node_modules/, tsconfig, *.map) ├── src/index.ts # КОНТРАКТ: экспорт main(pluginContext: PluginContext) ├── dist/ # собранный код (у автора — единственный публикуемый исходник) ├── node_modules/ # ставит инсталлятор LM Studio (node-plugin-installer-v1) └── .lmstudio/ # генерирует сам LM Studio / lms dev — НЕ редактировать ├── entry.ts # бойлерплейт: читает env LMS_PLUGIN_CLIENT_IDENTIFIER / │ # LMS_PLUGIN_CLIENT_PASSKEY / LMS_PLUGIN_BASE_URL, │ # создаёт LMStudioClient, вызывает import("../src/index.ts") │ # → main(pluginContext) → selfRegistrationHost.initCompleted() └── production.js # 0.4.26+: тонкий ESM-лаунчер (~10 КБ), в рантайме # импортирует ../src/index.ts (node 25 исполняет TS); # dist грузится цепочкой импортов. До 0.4.26: esbuild-бандл.
Запуск: процесс LM Studio сам спавнит node ./.lmstudio/production.js
(проверить: lsof -a -p <pid> -d cwd, родитель = LM Studio.app).
Env: LMS_PLUGIN_CLIENT_IDENTIFIER, LMS_PLUGIN_CLIENT_PASSKEY, LMS_PLUGIN_BASE_URL.
Модель рантайма 0.4.26+ (проверено 06.11.2026, инцидент релиза):
.lmstudio/production.js — не самодостаточный бандл, а лаунчер, импортирующий
../src/index.ts в рантайме. Следствия:
src/ обязателен в активной папке — без него плагин падает при старте
(ERR_MODULE_NOT_FOUND .../src/index.ts) и UI показывает «недоступен» (красный);dist/ НЕ требует пере-бандлинга — обновил dist, перезапусти плагин;Возможные хуки PluginContext (регистрация только одного на каждый):
| Хук | Назначение |
|---|---|
withToolsProvider(fn) | список Tool для модели (взаимно исключает PredictionLoopHandler) |
withPromptPreprocessor(fn) | (ctl, userMessage) => string | ChatMessage — обработка перед моделью |
withConfigSchematics(cs) | настройки per-chat (UI: чат → конфигурация плагина) |
withGlobalConfigSchematics(cs) | настройки на всё приложение (API-ключи и т.п.) |
withPredictionLoopHandler(fn) | полный контроль цикла предсказания (не совместим с tools) |
withGenerator(fn) | плагин как генератор |
maestro использует три: ConfigSchematics + ToolsProvider + PromptPreprocessor
(dist/index.js → main()).
| Путь | Роль |
|---|---|
~/ai-projects/LM_Studio/maestro | рабочий клон (здесь). owner=rura, rev 81, git, src/index.ts-шим, node_modules (233MB, скопированы из активного) |
~/.lmstudio/extensions/plugins/brdcastro/maestro | активный установленный экземпляр — именно он обслуживает чаты (процесс node ./.lmstudio/production.js, родитель LM Studio). src/index.ts = шим, добавлен 30.09 |
~/.lmstudio/apps/bionic/extensions/plugins/brdcastro/maestro | копия для приложения Bionic (общие ~/.lmstudio) |
~/lmstudio-plugins/proverennye-iskhodniki/brdcastro__maestro | резервная копия (тоже rev 81, без src) |
~/lmstudio-plugins/karantin/brdcastro__maestro-broken | карантин (сломанная сборка) |
Важно: автор публикует только dist/ (src/ в .lmsignore). TypeScript-исходников
везде нет — разработка ведётся напрямую в dist/*.js (CommonJS, структура 1:1 как у TS,
имена функций не искажены).
Что делает lms dev (проверено):
Типовой итерационный цикл:
Пока работает lms dev, в LM Studio зарегистрированы два maestro:
установленный brdcastro/maestro и dev dev/rura/maestro. Чтобы модель вызывала
инструменты из dev-версии, в UI (Integrations/Плагины) отключите установленный
brdcastro/maestro на время тестов (иначе возможны дубликаты инструментов в промпте
и вызовы «старых»). После тестов: вернуть как было. Проверить состояние визуально —
API/CLI списка плагинов нет.
Критично: убитый dev-сервер = dev-плагин исчез. Если в текущем чате модель уже
вызывала dev-инструменты — перезапустите lms dev перед продолжением, иначе
следующий tool-call упадёт. Установленный brdcastro/maestro от этого не страдает.
Тест-харнесс чистых модулей dist/ — без LM Studio и сети, ноль новых
зависимостей (встроенные node:test + node:assert/strict):
Системного node/npm на машине нет — раннер использует бандл-нод LM Studio
(v25). Переопределение: MAESTRO_NODE=/path/to/node bash test/run.sh.
Покрытие (базовый A2-набор 61 тест; live-харнесс 07.11.2026 — 135 тестов):
| Файл | Модули |
|---|---|
test/core.test.js | errorCodes, outputLimits, shared (validatePath, createSafeToolImplementation), projectMemory, workflowCoordinator, spillToDisk |
test/loopGuard.test.js | loopGuard + denialTracker (module-scoped трекеры: reset в beforeEach) |
test/tfidf.test.js | tokenize + TfIdfIndex |
test/engine.test.js | RetrievalEngine (embedding стабится через require.cache; db — фейк) |
Правила:
Вариант A — горячая замена dist (проверено 06.11.2026 в 0.4.26+; основной способ):
Пере-бандлинга не нужен: лаунчер грузит src→dist в рантайме. Один tool-call в
момент перезапуска может упасть — ожидаемо. Проверка: журнал
~/.maestro-toolbox/logs/tool-calls.jsonl пополняется, contextGauge в
.plugin_state.json.
Вариант B — полный переустан (менялись манифест/зависимости): in-place в 0.4.26 запрещён, только через внешнюю копию:
(инцидент 06.11.2026: шаг с src пропущен → плагин «недоступен»; восстановлено копированием src; полный разбор — в памяти проекта и git log)
Отдельный путь — публикация своего артефакта: lms push (см. ниже) → в LM Studio
установить rura/maestro из Hub. Минус: в системе будут два плагина с одинаковыми
именами инструментов — использовать, только если вариант A не подходит.
Публикация уважает .lmsignore (в Hub уйдёт dist/ без src/, node_modules и карт).
Каждый push = новая revision.
dist/tools/callJournal.js — loopGuard пишет метаданные каждого tool-call (JSONL)
в ~/.maestro-toolbox/logs/tool-calls.jsonl:
ok, error (+code), loop_blocked (+count), streak_blocked (+code), (+code);При инциденте (ст. 10.1) — смотреть хвост журнала перед падением: tail -20 ~/.maestro-toolbox/logs/tool-calls.jsonl (B3: журнал в протокол инцидента).
| Команда | Назначение |
|---|---|
lms clone <owner/name> [path] | скачать артефакт из Hub (owner в manifest переписывается на вас) |
lms dev | dev-сервер в текущей папке (--install — установить вместо сервера; --yes; --no-notify) |
lms push [flags] | загрузить артефакт текущей папки в Hub |
lms login / lms logout / lms whoami | аутентификация |
lms ps, lms server status | диагностика (модели, сервер) |
Инструмент:
Настройки (per-chat):
Типы полей: string, boolean, numeric, select (и scope для группировки).
Чтение значений — через ToolsProviderController / контроллеры (см. dist/tools/* — там
реальные примеры чтения конфига во всех tools maestro).
Свойства ToolCallContext: status(), warn(), signal (AbortSignal — слать в
долгие операции), callId. Ошибки: возвращаемая строка = «попробуй иначе», throw =
авария, warn = мелочь.
lms dev --install изнутри extensions/plugins/... запрещён
(«The plugin to install must not be located in the plugins folder») — только из
внешней копии; при этом установщик ставит пакет без src/ → возвращать руками.src/index.ts → relative-импорты из dist/ инлайнятся → .lmstudio/dev.js;[esbuild] build finished, watching..., [Tools Prvdr.] Register with LM Studio,
[PromptPreprocessor] Register with LM Studio);dist/index.js → [esbuild] build started (change: "dist/index.js") → build finished → авто-перерегистрация хуков.denied<file>.1 (одна копия), байтовый счётчик lazily;callJournal.setPath() (A2-харнесс).lms dev, lms dev --install, перезапуск LM Studio.lms не в PATH: ~/.lmstudio/bin/lms (или npx lmstudio install-cli).node_modules — нативные модули (better-sqlite3, sharp, sql.js). Копировать между
копиями того же Mac можно (одна архитектура arm64); после смены пакетов — npm ci.npx hyperframes);
кэш браузера не нужен..lmsignore исключает src/ из публикации — если начнёте вести полноценный TS-источник,
сначала решите: публикуем src (убрать строку из .lmsignore) или остаёмся на dist.lms ps + свободная RAM ≥ размер модели + 10GB (правило из инцидента 04.11).~/.lmstudio — плагины у Bionic в
~/.lmstudio/apps/bionic/extensions/plugins/; изменения в общем каталоге видны обоим.export PATH="$HOME/.lmstudio/bin:$PATH" # lms не в PATH по умолчанию
cd ~/ai-projects/LM_Studio/maestro
lms dev --no-notify # dev-сервер; Ctrl+C — остановка
править dist/*.js (или src/index.ts) → авто-пересборка → тест в чате LM Studio
bash test/run.sh # из корня клона
~/.lmstudio/.internal/utils/node --test test/*.test.js # то же, явно
ACTIVE=~/.lmstudio/extensions/plugins/brdcastro/maestro
cp -R dist "$ACTIVE"/
ls "$ACTIVE/src/index.ts" >/dev/null || cp -R src "$ACTIVE"/ # src обязателен лаунчеру
# затем Cmd+Q → открыть LM Studio (или выкл/вкл плагина в UI)
A=~/.lmstudio/extensions/plugins/brdcastro/maestro
rm -rf /tmp/maestro-release && cp -R "$A" /tmp/maestro-release
rm -rf /tmp/maestro-release/.lmstudio
cd /tmp/maestro-release && ~/.lmstudio/bin/lms dev --install -y
cp -R ~/ai-projects/LM_Studio/maestro/src "$A"/ # установщик ставит пакет БЕЗ src!
# Cmd+Q → открыть LM Studio
cd ~/ai-projects/LM_Studio/maestro
lms push -y # публикует rura/maestro (owner из manifest.json)
lms push --write-revision # ещё записать revision в manifest.json
lms push --private # приватный артефакт (только при первом создании)
lms push --description "..." # описать
{ts, tool, paramsHash (sha1 tool+params, 12 hex), ms, status, code?, count?}
import {
LMStudioClient, // клиент (в плагине создаётся бойлерплейтом из env)
createConfigSchematics, // билдер настроек
tool, // tool с zod-схемами параметров
rawFunctionTool, // tool с raw JSON-Schema
type PluginContext,
type ToolsProvider, // (ctl) => Promise<Tool[]>
type PromptPreprocessor, // (ctl, userMessage) => Promise<string | ChatMessage>
type ToolCallContext, // { status(text), warn(text), signal: AbortSignal, callId }
} from "@lmstudio/sdk";
import { z } from "zod";
const myTool = tool({
name: "my_tool",
description: "Чем полезен (модель читает!)",
parameters: { path: z.string().describe("путь"), count: z.number().int() },
implementation: async ({ path, count }, ctx) => {
ctx.status("Читаю файл..."); // видно в UI, не в промпте
ctx.warn("мелкая проблема, уже обработана");
return "строковый результат"; // или return "Error: ..." для повторяемого вызова
// throw — только для фатального
},
});
export const cfg = createConfigSchematics()
.field("myDir", "string", { displayName: "📁 Dir", subtitle: "..." }, "")
.field("myFlag", "boolean", { displayName: "⚡ Flag" }, false)
.field("count", "numeric", { min: 1, max: 15, int: true, slider: { step: 1, min: 1, max: 15 } }, 5)
.field("mode", "select", { options: [
{ value: "a", displayName: "A" }, { value: "b", displayName: "B" }] }, "a")
.build();
export PATH="$HOME/.lmstudio/bin:$PATH"
cd ~/ai-projects/LM_Studio/maestro
git status # чистое состояние?
lms dev --no-notify & # dev-сервер
# правим dist/*.js → hot-reload → тест в чате
# (в UI: отключить brdcastro/maestro, включить dev/rura/maestro)
# готово:
kill %1 # dev-плагин_unregister
git add -A && git commit -m "..." # фиксация
# в прод (горячая замена; ст.6.1):
ACTIVE=~/.lmstudio/extensions/plugins/brdcastro/maestro
cp -R dist "$ACTIVE"/
ls "$ACTIVE/src/index.ts" >/dev/null || cp -R src "$ACTIVE"/
# затем Cmd+Q → открыть LM Studio (или выкл/вкл плагина в UI)
lms dev --install изнутри extensions/plugins/... запрещён
(«The plugin to install must not be located in the plugins folder») — только из
внешней копии; при этом установщик ставит пакет без src/ → возвращать руками.src/index.ts → relative-импорты из dist/ инлайнятся → .lmstudio/dev.js;[esbuild] build finished, watching..., [Tools Prvdr.] Register with LM Studio,
[PromptPreprocessor] Register with LM Studio);dist/index.js → [esbuild] build started (change: "dist/index.js") → build finished → авто-перерегистрация хуков.denied<file>.1 (одна копия), байтовый счётчик lazily;callJournal.setPath() (A2-харнесс).lms dev, lms dev --install, перезапуск LM Studio.lms не в PATH: ~/.lmstudio/bin/lms (или npx lmstudio install-cli).node_modules — нативные модули (better-sqlite3, sharp, sql.js). Копировать между
копиями того же Mac можно (одна архитектура arm64); после смены пакетов — npm ci.npx hyperframes);
кэш браузера не нужен..lmsignore исключает src/ из публикации — если начнёте вести полноценный TS-источник,
сначала решите: публикуем src (убрать строку из .lmsignore) или остаёмся на dist.lms ps + свободная RAM ≥ размер модели + 10GB (правило из инцидента 04.11).~/.lmstudio — плагины у Bionic в
~/.lmstudio/apps/bionic/extensions/plugins/; изменения в общем каталоге видны обоим.export PATH="$HOME/.lmstudio/bin:$PATH" # lms не в PATH по умолчанию
cd ~/ai-projects/LM_Studio/maestro
lms dev --no-notify # dev-сервер; Ctrl+C — остановка
править dist/*.js (или src/index.ts) → авто-пересборка → тест в чате LM Studio
bash test/run.sh # из корня клона
~/.lmstudio/.internal/utils/node --test test/*.test.js # то же, явно
ACTIVE=~/.lmstudio/extensions/plugins/brdcastro/maestro
cp -R dist "$ACTIVE"/
ls "$ACTIVE/src/index.ts" >/dev/null || cp -R src "$ACTIVE"/ # src обязателен лаунчеру
# затем Cmd+Q → открыть LM Studio (или выкл/вкл плагина в UI)
A=~/.lmstudio/extensions/plugins/brdcastro/maestro
rm -rf /tmp/maestro-release && cp -R "$A" /tmp/maestro-release
rm -rf /tmp/maestro-release/.lmstudio
cd /tmp/maestro-release && ~/.lmstudio/bin/lms dev --install -y
cp -R ~/ai-projects/LM_Studio/maestro/src "$A"/ # установщик ставит пакет БЕЗ src!
# Cmd+Q → открыть LM Studio
cd ~/ai-projects/LM_Studio/maestro
lms push -y # публикует rura/maestro (owner из manifest.json)
lms push --write-revision # ещё записать revision в manifest.json
lms push --private # приватный артефакт (только при первом создании)
lms push --description "..." # описать
{ts, tool, paramsHash (sha1 tool+params, 12 hex), ms, status, code?, count?}
import {
LMStudioClient, // клиент (в плагине создаётся бойлерплейтом из env)
createConfigSchematics, // билдер настроек
tool, // tool с zod-схемами параметров
rawFunctionTool, // tool с raw JSON-Schema
type PluginContext,
type ToolsProvider, // (ctl) => Promise<Tool[]>
type PromptPreprocessor, // (ctl, userMessage) => Promise<string | ChatMessage>
type ToolCallContext, // { status(text), warn(text), signal: AbortSignal, callId }
} from "@lmstudio/sdk";
import { z } from "zod";
const myTool = tool({
name: "my_tool",
description: "Чем полезен (модель читает!)",
parameters: { path: z.string().describe("путь"), count: z.number().int() },
implementation: async ({ path, count }, ctx) => {
ctx.status("Читаю файл..."); // видно в UI, не в промпте
ctx.warn("мелкая проблема, уже обработана");
return "строковый результат"; // или return "Error: ..." для повторяемого вызова
// throw — только для фатального
},
});
export const cfg = createConfigSchematics()
.field("myDir", "string", { displayName: "📁 Dir", subtitle: "..." }, "")
.field("myFlag", "boolean", { displayName: "⚡ Flag" }, false)
.field("count", "numeric", { min: 1, max: 15, int: true, slider: { step: 1, min: 1, max: 15 } }, 5)
.field("mode", "select", { options: [
{ value: "a", displayName: "A" }, { value: "b", displayName: "B" }] }, "a")
.build();
export PATH="$HOME/.lmstudio/bin:$PATH"
cd ~/ai-projects/LM_Studio/maestro
git status # чистое состояние?
lms dev --no-notify & # dev-сервер
# правим dist/*.js → hot-reload → тест в чате
# (в UI: отключить brdcastro/maestro, включить dev/rura/maestro)
# готово:
kill %1 # dev-плагин_unregister
git add -A && git commit -m "..." # фиксация
# в прод (горячая замена; ст.6.1):
ACTIVE=~/.lmstudio/extensions/plugins/brdcastro/maestro
cp -R dist "$ACTIVE"/
ls "$ACTIVE/src/index.ts" >/dev/null || cp -R src "$ACTIVE"/
# затем Cmd+Q → открыть LM Studio (или выкл/вкл плагина в UI)