Методы служб платформы
Методы служб платформы: настройки, языки, наблюдение и журнал, источники, вход для программ, помощник и профиль.
Введение
Документ — часть договора Обмен с ядром: методы функций платформы, которыми пользуются мастерская и другие части. Уровни настроек и языки — Настройки, сведения, которые платформа записывает о себе, — Устройство платформы, 3.8. Коды отказов — Коды ошибок.
1 Настройки
Файлы уровней принадлежат функции настроек (Настройки, раздел 1). Уровень session — только память функции, не файл.
settings.get—{ "key" }или все значения; сprocess_idдобавляет ключи процесса; сессия накрывает всё. Сlevel: "process"иprocess_id— только значения, записанные на уровне процесса, как они записаны: так их берёт экспорт процесса;settings.set—{ "key", "value", "level" }(core|system|user|process|session);processтребуетprocess_idи принимает, кроме ключей схем, свободный ключ процесса — имя, которое параметр узла называет${имя}([A-Za-z_][A-Za-z0-9_]*), без схемы и без проверки значения; на других уровнях ключ без схемы —settings_unknown_key; безlevel—user;sessionне пишет файл; ключиcore.*на уровнях кромеsessionвсегда вconfig/core.json. Ответ —{ key, value, level, restart }, гдеlevel— уровень, куда значение записано на деле; событиеsettings.changed—{ key, level, restart };settings.reset—{ "key" },{ "prefix": "ui." }или{ "group": "core" | "ui" | "other" }; опциональноlevel, дляprocess—process_id: снять переопределение с уровня (ключ удаляется из файла или из сессии), значение снова берётся из схемы и нижних уровней; безlevel—core.*изconfig/core.json, остальные изconfig/user.json, и все названные ключи — из сессии: сброс без уровня возвращает умолчание. Ответ —{ keys, values, level }:values— значения ключей после сброса,level— уровень сброса, а безlevelв запросе —core,userилиmixed, если сняты ключи обоих видов; событиеsettings.changed—{ reset: keys, level };settings.ensure—{ "level": "process", "process_id" }: создать пустой документ настроек процесса, если его нет;settings.schema— схемы всех хозяев:{ "sections": [{ "id", "owner", "group", "keys": [ключ, …] }], "keys": { ключ: { "type", "default", "default_by"?, "restart", "min"?, "max"?, "choices"?, "section", "group", "owner" } } }. Подразделы идут по крупным разделам (core,ui,other), внутри раздела — по id хозяина, у хозяина — в порядке его файла схемы. Текстов в ответе нет: окно берёт их из словаря по ключамsetting.*(Настройки, раздел 2);settings.schema.register—{ "schema" }, гдеschema— содержимое файла схемы хозяина (ogas.settings-schema/1). Хозяин — тот, кого ядро называет отправителем вызова (source, Обмен с ядром, раздел 3): ключи и подразделы только с префиксом{хозяин}.; повтор того же хозяина заменяет его схему целиком, и хозяин повторяет регистрацию, когда функция настроек поднимается заново (function.ready); чужой ключ или схема с ошибкой —settings_invalid, схема другого хозяина —settings_invalid_owner. Ответ —{ "owner", "keys" }. Публикуетsettings.schema.registered—{ function_id, keys }: хозяин передал схему своих ключей; значения при этом не меняются, поэтому это неsettings.changed.- Схему ключей
core.*функция настроек не регистрирует у себя, а при запуске получает у ядра запросомcore.settings.schema. - Значение в файле уровня, которое не проходит проверку по схеме, не используется: берётся значение более широкого уровня, а функция публикует
settings.value_invalid{ key, path, value, error_code: "settings_value_invalid", message }— один раз на файл, ключ и значение;message— короткая причина для того, кто разбирает отказ по журналу, не текст для человека.
2 Локализация
i18n.translate—{ "key", "language"? }: текст ключа на языкеlanguage, без него — на языке интерфейса; язык, которого не допускает схемаi18n.language, — отказinvalid_request. Ответ —{ key, language, text }. Текст отдаётся как записан в словаре: подстановки параметров нет, тексты словарей их не принимают. Папки — собственныеfunctions/i18n/localesплюс пути изcore.locales; при отсутствии ключа в папке ответом возвращается сам ключ, а событиеi18n.key_missing—{ error_code: "i18n_key_missing", key, language }— открывает проблему, одну на ключ;i18n.catalog—{ "language" }(по умолчанию текущий): весь словарь языка одним ответом{ language, catalog }; мастерская берёт его один раз и ищет ключи у себя;i18n.language.get— запрос без параметров: язык интерфейса, как он задан в эту минуту, и языки, которые допускает его схема,{ language, choices }. Другие части узнают язык только так: настройкаi18n.languageпринадлежит функцииi18nи договором для других частей не является (Правила разработки, 2.6.6);i18n.language.set— команда{ language }: функцияi18nпроверяет, что язык допустим (иначеinvalid_request), и сама записывает свою настройку; ответ{ language }. Так язык меняет мастерская, не зная ключа настройки.- Язык интерфейса — настройка
i18n.languageфункцииi18n; окно настроек пишет её обычнымsettings.set, как любую другую, иi18n.translate,i18n.catalogиi18n.language.getберут язык из неё.
При знакомстве (handshake) функция может объявить locales — относительные папки (functions/<id>/locales, modules/<id>/locales). Ядро отдаёт их запросом core.locales. Функция i18n не обходит папки соседей сама.
3 Наблюдаемость
observe.logs.query—{ "run_id"?, "trace_id"?, "level"?, "limit"? }: общий журналlogs/events-<ГГГГ-ММ>.jsonl— от самого нового месяца назад, пока не наберётсяlimitзаписей,logs/events.jsonl, если он есть, последним (неcore.jsonl); сrun_id— файл прогона, если он есть. Запрос ничего не пишет. Нет файла — пустой список.level—info|warn|error; другое значение — отказinvalid_request, а не пустой ответ. Безlimitотдаются 50 последних записей. Недописанный хвост без\nне читается;observe.logs.remove— команда{ "before": "ГГГГ-ММ" }: удаляет месяцы общего журнала раньше названного иlogs/events.jsonl, если его последняя запись раньше; месяц позже нынешнего — отказinvalid_request, нынешний не удаляется никогда. Ответ —{ before, removed }, имена удалённых файлов; удаление публикуется событиемlogs.removed{ files, before, by },by—commandилиsetting. Месяцы, которых не держит настройкаobserve.logs_keep_months, функция удаляет сама так же — при запуске, в начале месяца и после правки настройки.observe.problems.list— опционально{ "status": "open"|"resolved" }: открытые проблемы (open: true) или закрытые; другое значение — отказinvalid_request, без поля — все. Проблема — сгруппированный отказ (problem_id,code,severity,open,count,first_seen/last_seen), а не копия каждого события; её поля — Форматы файлов, раздел 13;observe.problems.resolve—{ "problem_id" }: команда; публикуетproblem.resolved.observe.space— запрос без параметров:{ parts: [{ key, title_key, bytes, clear_method? }] }— части места и сколько каждая занимает на диске;title_key— название части в словаре хозяина,clear_method— команда, которая убирает восстановимое в этой части (её зовут с{ part: key }); журналы убираются по месяцам (observe.logs.remove).
4 Источники
Функция sources (Мастерская, 5.6; угрозы — Защита, 3.14). В сеть она ходит программой curl системы, с прокси и сертификатами, которые видит система, и только когда её просят. Витрину ogas.space она читает только вместе с подписью ключом сайта (Форматы файлов, 21.5): подпись не сходится или её нет — отказ source_signature_bad у sources.search, sources.item и sources.platform.
sources.list— запрос без параметров:{ sources: [{ source, kind, url, unchecked }] }— источники по настройкам функции:ogas— витрина O.G.A.S.,catalog-1,catalog-2… — витриныsources.catalogs,huggingface,civitai. Источник с пустым адресом не перечисляется.unchecked— витрина не на ogas.space (адрес не начинается сhttps://ogas.space/): что в ней, никто не проверял; у Hugging Face и Civitai —false, они держат нейросети, а не код.sources.facets— запрос{ source }: по чему источник отбирает и в каком порядке отдаёт —{ filters: [{ key, values }], sorts }: у Hugging Face фильтрыtaskиlibrary, у Civitai —typeиbase, у витрины —what; порядки —downloads,likes,newest.sources.search— запрос{ source, text?, filters?, sort?, related? }:{ items, more }, не большеsources.resultsвещей;filters—{ key: value }изsources.facets,sort— один из его порядков,related—{ relation, id }у Hugging Face: модели, сделанные изidтак:quantized,finetune,adapter,merge. Вещь —{ id, title, what, kind?, category?, base?, author?, downloads?, likes?, updated?, license?, size?, parameters?, gpu_mb?, profile?, preview },category— задача или тип, как их называет источник,base— библиотека у Hugging Face, базовая модель у Civitai,parameters— сколько у нейросети параметров, если источник называет,gpu_mb— сколько видеопамяти нужно программе или модулю витрины, если она называет,profile— номер профиля автора на ogas.space, если витрина называет,what—program,module,networkилиpiece— заготовка интерфейса,size— байты, если источник их называет,preview— есть ли у вещи картинка. Пустойtext— витрина целиком, у Hugging Face и Civitai — самое скачиваемое. Запрос уходит на сайт источника.sources.item— запрос{ source, id, version? }: вещь целиком —{ id, title, what, kind?, category?, author?, license?, description?, page?, gated, files, size, versions, version, version_id, base, relations, gpu_mb?, profile? }:versions— версии вещи{ id, name, base?, updated? },version_id— какая показана,version— её название (у Civitai; безversionв запросе — последняя),base— от какой модели она сделана,relations— какие родственные у неё бывают (quantized,finetune,adapter,merge);- файл —
{ path, size, sha256?, runs_code, chosen, role, variant? }:role—weights,part:<папка>,adapter,config,tokenizer,vae,docs,pictureилиother;variant— чем эти веса отличаются от других: уровень квантования, точность, урезанность. Когда источник роль и вариант не называет, их читают по имени файла только у нейросети, а файлы программы и модуля —other, без варианта; runs_code— формат, который при чтении исполняет код;chosen— что брать, если человек не выбрал другое:.safetensors, когда они есть, и всё, кромеruns_code;size— сколько весят выбранные;weights— есть ли у вещи веса вообще,safe_weights— есть ли среди них.safetensors: без них веса выбирает сам человек;gated— источник требует вход или согласие с условиями: такую вещь платформа не скачивает.sources.preview— запрос{ source, id }: картинка найденного для плитки —{ media_type, data },data— содержимое в base64, или{ media_type: null }, если её нет или она не PNG, JPEG, WebP или GIF. Адрес берётся из последнего поиска этого источника, не из вызова; картинка больше 2 МиБ не берётся (Защита, 3.14).sources.download— команда{ source, id, version?, files, kind?, name? }: начать загрузку файловfiles— путей изsources.item; нейросети — с видомkindи именемname, под которыми она встанет в папку нейросетей. Ответ сразу —{ download_id, size }, ход — событием. Отказ до начала:source_gated,source_too_big— большеsources.max_gib,source_no_room— больше свободного места,source_file_bad— путь, которого нет у вещи или который выходит из её папки,model_exists— нейросеть с таким именем уже есть.sources.download.cancel— команда{ download_id }: остановить загрузку; её папка убирается. Нет такой идущей —download_not_found.sources.downloads— запрос без параметров:{ downloads }— загрузки сеанса в виде событияsources.download.changed, самые новые первыми.sources.space— запрос без параметров:{ parts: [{ key, title_key, bytes, clear_method? }] }— части места и сколько каждая занимает на диске;title_key— название части в словаре хозяина,clear_method— команда, которая убирает восстановимое в этой части (её зовут с{ part: key }).sources.space.clear— команда{ part: "downloads" }: убирает скачанное и не принятое; папка идущей загрузки остаётся. Ответ{ cleared, removed }.sources.platform— запрос{ check? }:{ own, version?, page?, newer, checked }— номер платформы и что последний взгляд на витрину O.G.A.S. сказал о новой версии;check: true— посмотреть сейчас. Витрину смотрят только проверенную (ogas.space), страница новой версии — только страница этого сайта. Витрину смотрят по кнопке «Проверить» в «Состоянии» и при запуске, если включена настройкаsources.check_on_start(по умолчанию включена); ничего при этом не скачивается и не ставится.- Событие
sources.platform.newer—{ own, version, page }: вышла новая версия; мастерская говорит об этом и показывает номер в баре «Платформа». - Событие
sources.download.changed—{ download_id, source, unchecked, id, title, what, state, done, size, file?, folder?, document?, kind?, name?, error_code?, message? }.state—going,done,failedилиcancelled;doneиsize— байты;file— какой файл качается;folder— у кончившейся программы, модуля и заготовки интерфейса папка вdownloads/, откуда их принимают;document— у заготовки её документ, который принимаетcanvas.piece.import. Пока загрузка идёт, событие выходит не чаще раза в секунду.unchecked— адрес витрины, которую никто не проверял, если загрузка оттуда, иначеnull: окно спрашивает о доверии, прежде чем принять программу или модуль.
5 Вход для программ человека
Функция gate — вход, через который программа человека (сценарий OGAS SDK, редактор) говорит с платформой. Вход закрыт, пока настройка gate.door не равна open; закрытие рвёт все соединения через него. Функция слушает TCP только на 127.0.0.1, порт — настройка gate.port (0 — свободный), сразу — не больше gate.clients программ. Где вход и его ключ, функция пишет в документ data/gate.json (ogas.gate/1): { format, port, key }, port — null, пока вход закрыт. Ключ — 32 случайных байта в шестнадцатеричном виде; он живёт, пока его не заменят.
Первое сообщение соединения — gate.hello { key, client? }: верный ключ — ответ { status: "ready" }, неверный или другое первое сообщение — отказ gate_unauthorized и закрытое соединение; молчание дольше 10 секунд закрывает соединение; программ уже столько, сколько пускает вход, — gate_busy. Дальше запросы программы идут ядру, как запросы окна, а события ядра приходят ей уведомлением event. Нельзя — отказ gate_not_allowed: методы ядра, кроме core.status, core.health и core.event.subscribe; методы gate.* и методы функций окна — тех, что в core.status названы interactive; settings.set ключа gate.*; settings.reset без ключа или ключа gate.*.
Методы функции для окна:
gate.status— запрос без параметров:{ open, port, programs, limit }— открыт ли вход, его порт, сколько программ вошло и сколько пускает.gate.key— команда без параметров:{ key, document }— ключ, чтобы человек передал его программе сам, и где он записан. Ключа ещё нет — команда создаёт его и записывает; создать не вышло —gate_no_key.gate.key.renew— команда без параметров: новый ключ; все программы, вошедшие со старым, выходят. Ответ{ renewed: true }.
6 Помощник
Функция assistant — помощник мастерской: человек пишет задачу словами, а сеть, которую он подключил, собирает программы и модули инструментами платформы, проверяет и пробует их и говорит, что сделала. Сеть — модуль с "role": "assistant_network" (вход request, выход reply); готовые сети приходят с OGAS SDK в sdk/networks, ключ сети лежит в .env её модуля и в функцию помощника не попадает.
Доступ задачи — draft или extended. С draft помощник меняет только черновики и модули, которые сам создал (их список — data/assistant/own.json, ogas.assistant-own/1), и не включает программы. С extended — любые программы и модули человека, кроме сетей помощника, и включает программы. Ни в каком доступе у помощника нет инструментов, которые читают секреты, меняют настройки или удаляют.
Задача идёт в своём потоке: сеть отвечает, функция выполняет инструменты, которые она позвала, и отдаёт ей их ответы, пока сеть не ответит без инструментов. Задача останавливается, когда израсходовала assistant.max_steps обращений к сети или assistant.task_budget токенов, и ждёт assistant.task.go_on. Задача пишется после каждого шага в data/assistant/tasks/<task_id>.json (ogas.assistant-task/1) и говорит о себе событием assistant.task.changed.
assistant.network.get— запрос без параметров:{ format, module_id, params, environment }— выбранная сеть (ogas.assistant-network/1,data/assistant/network.json).assistant.network.set— команда{ module_id, params?, environment? }: выбрать сеть;environment— программа, в чьём окружении Python идёт модуль сети, если ему нужны пакеты. Модуль не сеть помощника —assistant_not_a_network.assistant.task.start— команда{ text, access? }: новая задача; ответ{ task_id }. Сети нет —assistant_no_network.assistant.task.say— команда{ task_id, text, access? }: человек говорит в задаче ещё; задача идёт дальше. Пока она работает —assistant_task_busy.assistant.task.go_on— команда{ task_id }: задача, остановленная пределом, идёт дальше с новым пределом.assistant.task.stop— команда{ task_id }: задача останавливается перед следующим шагом;{ task_id, stopping }.assistant.task.get— запрос{ task_id }: задача целиком —{ task_id, title, created, state, access, messages, log, usage, error, working };state—going,answered,stopped,limitилиfailed;log— действия{ at, tool, arguments, ok, said }. Нет такой —assistant_task_not_found.assistant.tasks— запрос без параметров:{ tasks: [{ task_id, title, state, created, access }] }, новые первыми.- Событие
assistant.task.changed—{ task_id, state? , working? }.
7 Профиль
Функция profile — профиль человека на ogas.space, его посылки, отправки и письма, и что сайт говорит о людях: доска обращений, отзывы, известные ошибки, профили. Что от чего защищает — Защита, раздел 8; документы — Форматы файлов, раздел 21. В сеть функция ходит программой curl системы: отправляет — только по команде человека, читает — по команде или при запуске, если включена настройка profile.check_on_start. Всё, что она читает с сайта, принимается только с верной подписью ключом сайта; иначе — site_signature_bad.
Главный ключ приходит в вызов кодом (code) или файлом ключа (file — путь, password?) и забывается, как только вызов кончился.
profile.state— запрос без параметров:{ exists, card, number, device, ask_at_start }— есть ли профиль на этом компьютере, его карточка, номер на сайте (если сайт его назвал), открытая часть ключа этого компьютера;ask_at_start— показывать ли первое окно (настройкаprofile.ask_at_start).profile.create— команда{ card }: новый профиль. Ответ{ code, parcel }— код восстановления, один раз, и посылка карточки, которая уходит на сайт (её ход — событиемprofile.sending.changed). Профиль уже есть —profile_exists.profile.join— команда{ code | file, password?, card }: подключить этот компьютер к своему профилю; карточка уходит заново. Ответ{ parcel }. Код не сходится —key_code_bad; пароль не подходит —key_password_bad; файл неogas.key/1—key_file_bad.profile.key.write— команда{ code, path, password? }: записать файл ключа туда, куда сказал человек; с паролем код в нём зашифрован. Ответ{ path }.profile.card— команда{ card, code | file, password? }: изменить карточку; уходит посылкойprofile.profile.revoke— команда{ code | file, password? }: отозвать все компьютеры профиля, кроме этого.profile.delete— команда{ code | file, password? }: удалить профиль на сайте; имя и страница уходят, отправленное остаётся без имени. Профиль на этом компьютере убирается после того, как посылка ушла.profile.leave— команда без параметров: выйти из профиля на этом компьютере — ключи, отправки и письма этого компьютера удаляются; на сайте профиль остаётся.profile.send— команда{ what, fields }: посылка от ключа компьютера,what— вид из таблицы 13 «Форматов файлов», кромеprofile,revoke,delete; уofferвместо файлов —things: [{ process_id, version? } | { module_id } | { piece: { id, version?, document } }]: вещь собирает её хозяин — программу с её модулями пакетом экспорта функция графа (process.export), модуль — функция модулей (module.export), — и функция профиля берёт папку, которую тот назвал в ответе; окружения, кэш, скрытые файлы и.envне уходят, у модуля не на Python не уходит собранная программа. Уbugключ писем для ответа функция ставит сама. Ответ сразу —{ parcel }, ход — событием. Профиля нет —profile_none; поля не те —parcel_bad; вещи нет —thing_not_found; в вещи файл не текст и не картинка —thing_binary; у модуля не на Python нетCargo.lock—thing_no_lock; больше пределов —parcel_too_large.profile.offer.look— запрос{ things }, как уoffer: что уйдёт — по вещи файлы с размерами и что не уйдёт и почему; ничего не отправляет.profile.resend— команда{ parcel }: отправить ещё раз посылку, которая не ушла; она уже подписана, главный ключ не нужен. Такой нет —parcel_not_found.profile.sent— запрос без параметров:{ sent, unsent }— свои отправки (ogas.sent/1), новые первыми, и подписанные, но не ушедшие:{ id, what, title, made, going },going— идёт ли сейчас. Неотправленная посылка ждёт вdata/profile/outbox/, а больше предела документа ядра — в памяти до остановки платформы.profile.check— команда без параметров: прочесть с сайта состояния и письма; ответ{ changed, letters }— сколько отправок сменили состояние и сколько новых писем. Сайт не ответил —site_unreachable.profile.letters— запрос без параметров:{ letters }— открытые письма (ogas.letters/1), новые первыми.profile.site— запрос{ file }:requests,reviewsилиprofilesс сайта, проверенные подписью, — доска обращений, отзывы и известные ошибки, профили. Сайт не ответил —site_unreachable.- Событие
profile.changed—{ exists, number }: профиль создан, подключён, изменён, удалён или человек вышел. - Событие
profile.sending.changed—{ parcel, what, state, error_code?, detail? }:state—counting(задачка на счёт),sending,sent,failed; уfailed— код отказа: свой или ответ сайтаparcel_refusedс его кодом вdetail. - Событие
profile.checked—{ changed, letters }: взгляд на сайт кончился, при запуске тоже; мастерская говорит о новых письмах и сменившихся состояниях.