O.G.A.S. Русский

Modules

What a module is and how the platform deals with it: the folder and versions, the modes of life and unloading, the Python environment, the work folder, the memory of a node, parameters, neural networks.

Introduction

The document describes a module, how it is built into a working process, where its dependencies are put and what OGAS SDK is for. The owner of modules is the function modules. The format of the manifest — File formats, section 4, the messages of a module and the methods of the function — Methods of modules.

1 The purpose of a module

A module is a separate program that does one task: it gets a packet at its input and gives a result at its output. The purpose of a module is not limited. A person writes a module themselves or gets it ready from another person.

2 The module folder

modules/<module_id>/
  manifest.json            the manifest ogas.module/1
  main.py                  the entry point
  requirements.txt         Python dependencies, if any
  uv.lock | pylock.toml    exact versions of dependencies, if the author put them; the platform does not read them (section 5)
  requirements.freeze.txt  what pip installed, for diagnostics
  locales/{ru,en}.json     the name of the module, the texts of its parameters and ports (section 10)
  test_<module_id>.py      checks of the module without the platform, if the author wrote them

A ready module is added in one of two ways: its folder is put into modules/, or it is added together with a process from an export (process.inspect, then process.import, Building, installing and maintenance, 5.6). The list of modules is read again from the folder at each request; no restart is needed. The texts of a new module are seen at once too: at introduction the function of modules declares to the kernel the dictionary folder modules/*/locales, and the kernel finds the dictionaries of modules anew at each question (Exchange with the kernel, section 4). Then come the check of the manifest, installing dependencies, a test call and adding a node to the graph (Getting started, 6). All these actions are done in the workshop without copying by hand. A module is made and deleted, and whether the column of the graph offers it is decided, in the library of the workshop, and the environment of a program is installed in the window «Modules» of that program (The workshop, 5.6).

3 Versions

In one installation each module_id has one version. The version of a module in a process is written in one place — in modules.lock.json; the node of the graph does not keep it. It is written by the function of modules when the process is saved: it takes the version and the print from the installed module. A module that is not installed is not written into modules.lock.json. Before a run the function of the graph compares the written version with the installed one and passes it to module.execute; on a mismatch the start is refused (module_version_mismatch).

The print of the content. The files of a module can be changed without changing its version. For such a change to be found, the process remembers together with the version the print of the module — sha256 over the content of its files, without the environment, caches, diagnostics and symbolic links (a link is not part of the module and is not carried by an export). Before a run the print is compared with the installed module:

The print shows a change of files but does not name the author of the change: it is not a signature, and the module stays trusted code (Protection, section 1).

4 Modes, unloading and parallelism

How long the OS process of a module lives is declared by the field process of the manifest:

Unloading by resources. The function of modules keeps count of the started modules of all programs that are on and knows how much video memory each takes: the field resources.gpu_mb of the manifest. While the sum fits into the setting modules.gpu_budget_mb, the modules work at once; at 0 one module with gpu_mb > 0 uses the video card at a time. When there is no room for the next module, the function of modules unloads the one that has not worked longest — a long one or a service of any program that is on. A module is not unloaded during a step: a step that needs the video card waits for room no longer than its own term (timeout_ms), and if it does not get it, ends with the refusal module_gpu_full.

The memory of a node. A module is a tool, a node is its use: «writer» and «judge» on one model are two nodes and two memories. A module in a run is one for all its nodes, and the weights are loaded once, but each node has its own memory — the folder data/processes/<process_id>/state/<node_id>/; how nodes name a shared memory and how long it lives — The program: graph and runs, section 13. From the side of the module:

Parts of a result. A module can pass the result of a step in parts while it works (the notification partial, section 7): the text of an answer as it is generated, finished elements of a list. The parts are passed along the links of the output and are shown on the pulpit at once through a variable (The program: graph and runs, sections 7, 13). The answer to execute stays the final result of the step.

By default the calls of one module go one after another — from different runs of one program too. Calls at the same time are possible only if the manifest declares parallelism > 1: this is a permission of the module, not a promise of the platform.

Resources for all modules are set by the person in the settings of modules (the section «Resources for modules»):

The term of a step is set by the author of the module with the field timeout_ms of the manifest — an integer number of milliseconds, no less than 1. This term is the only one: the platform does not shorten it with a limit of its own and sets no terms of its own. The term is kept by the function of modules: if the module did not answer in time, it stops it (core.process.stop, then core.process.kill) and answers module_timeout. The function of the graph and the workshop wait for the answer to a step without a term of their own: the answer comes with the result, with module_timeout or with function_lost on a failure of the function of modules itself.

5 The Python environment

One Python environment is used for a working process, shared by all its modules. A process is a finished whole: one installation of dependencies, one set of versions. The modules stay separate OS processes.

The environment is made by uv, and identical files lie on disk once. The environments of processes are hard links to the files of packages in the common cache data/cache/uv/: each process has its own environment and its own set of versions, and a package that is the same in two processes takes room once. The cache lies in the data folder to be on the same disk as the environments: there is no hard link between disks. uv is the program named by the setting modules.uv (uv by default, looked for in PATH); if it is not there, installing ends with the refusal module_uv_not_found. uv does not download its own Python: the environment is made with the interpreter found by modules.python_candidates.

Where the environment lies and what happens on a clash of versions:

6 The work folder and result files

The OS process of a module is started in the work folder of the run in the folder of its process: data/processes/<process_id>/runs/<run_id>/work. A test call without a process gets its own folder data/module-tests/<module_id>/work. A service works longer than a run, so it is started in the memory folder of the process state/, and gets the work folder of the run in each execute in the field work_dir and puts result files there.

7 The protocol of a module

A module exchanges JSON-RPC 2.0 messages with the function of modules, one per line, through stdin and stdout (table 1).

Table 1 — The protocol of a module

Method Meaning
init the language of the interface; the module answers ready, the version of the protocol and its capabilities. Before the answer execute is not sent
execute facts about the run, the input data, the parameters of the node (section 10), result files, the memory folder of the node state_dir and the sign resumed — the memory in it is saved whole by this same module (section 4); the answer is the output data and the port
configure only to a service: the nodes of its module in this process with their parameters — [{ node_id, parameters }], the parameters as a step would get them (section 10) — at each coming up of the service: when the program is switched on and again after unloading, before the first step. A module that does not know the method answers method_not_found and works without it; another refusal — the service does not come up
cancel cancelling a particular execution_id
ping checking that a long module or a service works: the function of modules asks each one that is up once every modules.ping_interval_ms; one that did not answer within modules.ping_timeout_ms is stopped as lost — a step going ends with module_process_lost, a service comes up again for the next step — and the function tells of it with the event function.work_failed. A module must answer ping in the middle of a step too
suspend a module with suspend: true saves the memory of each node it served into the folder state_dir of that node and answers when it has saved; after the answer the function of modules ends it (section 4)

A module may send the notifications progress (the share of readiness), log, partial — a part of the result of a step (execution_id, port, data; section 4), signal — a signal to its own program (name, optional key and data): a branch that waits for it at a node signal goes on (The program: graph and runs, section 22) — and, if it is a service, emit — a packet at an output outside a step, the beginning of a new run (port, data and an optional node_id: a service of several nodes names which of them the packet is for; without a name the packet goes to all nodes of the module that have a link from this output). stdout belongs to the protocol: debugging text in it is not allowed and counts as damage of the protocol; diagnostics go to stderr.

The answer to execute and the notifications partial and emit name one of the outputs of the manifest; a module without outputs names no output. A refusal carries a code: a code of the contract of a module or a cause of the module itself, whose text lies in the dictionaries of the module (table 2). A module does not refuse in the name of the platform: a code of the platform it names becomes a cause of the module. An answer outside these rules does not count as a success — the step ends with module_process_lost; a notification outside them is not passed on, and this is reported. The fields of an answer and a refusal — Methods of modules, 1.2.

The stream stdout is limited the same way as the bus: a line longer than 4 MiB or more than 256 unread answers end the step with the error transport_overflow. So a module cannot quietly take all the memory of the platform.

A module declares whether its steps may be repeated: idempotent, non_idempotent or unknown. On this depend whether a run may be retried and resumed (The program: graph and runs, section 14). The platform promises that execute with one operation_id arrives at least once, not «exactly once». Guarding an outside action against being done again is the business of the module itself.

8 Modules in other languages

A module in any language is an executable file with the same protocol through stdin / stdout (runtime: "native"): the platform starts it directly. The protocol does not depend on the language; ready libraries exist for Python and for Rust (section 9), in another language the protocol is written by Methods of modules.

9 OGAS SDK

OGAS SDK is a set of tools for the authors of modules that keeps the modules of different authors compatible. There is an SDK for Python and one for Rust.

10 The parameters of a node

Everything the person sets for a module is expressed by one notion — the parameters of a node. There are no separate «module settings».

Table 2 — The texts of a module in the dictionaries

Text Key of the dictionary Required
the name of a parameter module.<id>.param.<name>.title yes
the explanation of a parameter: purpose, allowed values, behaviour without it module.<id>.param.<name>.help yes
the name of a value from a closed set module.<id>.param.<name>.choice.<value> yes, if there are choices
the name of an input module.<id>.input.<port>.title yes
the name of an output module.<id>.output.<port>.title yes
the hint of an input module.<id>.input.<port>.help yes
the hint of an output module.<id>.output.<port>.help yes
the text of a refusal for a cause of the module itself module.<id>.error.<code> no; without it the refusal is named by the common text of module_failed

These hints are shown by the sign «?» in the graph window (The workshop, section 5). The name of a port stands on the node as a row (The workshop, 5.3), so it is required; with the hint of a port the workshop says what a link to it will give, so that is required too. The check in make ci does not pass if a parameter or port of a module lacks a required text in Russian or English, or a text is written in the manifest.

The properties panel of a node in the workshop builds its fields by this schema: each parameter has a field of its type, an empty field means «the default of the manifest holds» (The workshop, section 5). For a network parameter the field is a choice among the networks of its kind in the library; a chosen network that is no longer there stays in the choice with a mark that it is not in the folder of networks. A parameter taken from a variable names it in the empty field and stays taken when other parameters of the node are saved — until a value is typed or chosen in its field.

11 Neural networks

A neural network is a neural network or other big data modules of different programs use: weights, dictionaries, voices. It lies in the library in one copy, not as a copy at each module or in the environment of each program (The workshop, 5.6). Which network a module takes and what else goes with it — an addition, a dictionary, a voice — the node chooses, in the workshop and on the pulpit.