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

Methods of modules

How the function of modules talks to a module — the messages of a step, a long module and a service — and its own methods: the list, installing the environment, starting a step, neural networks, networks of the assistant, secrets and files of a module.

Introduction

The document is a part of the contract Exchange with the kernel: the messages between the function of modules and a module through stdin and stdout, and the methods with which the function of modules answers other parts. The purpose, make-up and life cycle of a module — Modules. The refusal codes — Error codes.

1 The contract with a module

The messages that go through the stdin and stdout of a module. What each of them is for — Modules, section 7.

1.1 init

{
  "jsonrpc": "2.0",
  "id": "module-1",
  "method": "init",
  "params": {
    "language": "ru"
  }
}

language — the language of the interface, or null if the function i18n is unavailable (Settings, section 7). The sign resumed does not come in init: a module is one for all its nodes, and whether each node goes on from its saved memory is said by the step of this node (1.2).

The answer: { "status": "ready", "protocol": 1, "capabilities": ["execute"] }.

1.2 execute

{
  "jsonrpc": "2.0",
  "id": "module-3",
  "method": "execute",
  "params": {
    "context": {
      "process_id": "demo",
      "run_id": "run-1",
      "attempt_id": "attempt-1",
      "node_id": "echo_one",
      "operation_id": "op-1",
      "execution_id": "exec-1",
      "iteration_id": 0,
      "trace_id": "trace-1"
    },
    "input": { "text": "example" },
    "input_port": "input",
    "params": { "suffix": " / x" },
    "artifact_handles": ["sheet-1.svg"],
    "state_dir": "/…/data/processes/demo/state/echo_one",
    "resumed": false
  }
}

state_dir — the memory folder of the node of this step (its own or a shared one the node named in the field memory; the name comes in context.memory), resumed — true if the memory in it is saved whole by this same module — the same module, version and print — at the last unloading and confirmed by the answer (1.5): the node goes on from the saved place in any run and after a restart of the platform. A module is one for all its nodes; it keeps the memory of each node apart, by its folder, and reads it from the folder when it first serves the node (Modules, section 4). A test call without a process has neither field. In the SDK — state_dir(params) and resumed(params).

input_port — the input of the node the data came to: a module with several inputs learns it rather than guessing by the content. There is no such field when the rule all gathered data from several inputs into an object by their names.

models — the paths to the neural networks the parameters of the step of type model chose: «name of the parameter → full path» of the file or folder of the network; there is no such field if such parameters chose nothing. The chosen network is not there — the step does not reach the module: module_model_missing (Modules, section 11).

A service also gets work_dir — the absolute path to the work folder of the run: it is started in its own state folder and works longer than the run, so it puts result files there (Modules, section 6). A step module and a long one do not get work_dir: they are started in the work folder of the run.

Success: { "port": "success", "output": { "text": "..." }, "artifacts": [] }. In port the module names one of the outputs of its manifest, in output the object that goes along this output. A module without outputs names neither an output nor what goes along it.

Artifacts are the files a module leaves as the result of a run:

  1. The module works in the work folder of the run processes/<process_id>/runs/<run_id>/work of the data folder and makes its files there.
  2. In artifacts it lists those of them that are to become a result: as a path string ("result.txt") or an object { "path", "media_type" }. The path is only inside the work folder.
  3. The function of modules moves the file into the results of the run processes/<process_id>/results/<run_id>/ under its name — a folder in the path becomes part of the name, a taken name gets a number — and replaces the record with a reference { artifact_handle, kind, size, media_type, name }, where artifact_handle is the name of the file among the results.
  4. A picture, sound, video or file the module gives in output it names with a reference { "file": "out/frame.png" } — the same path as in artifacts. Having moved the file, the function of modules puts its name among the results into file and adds media_type, size and name — the file name from the path, if the module gave none of its own. So the output carries a reference to the file, which the node «Show», a variable and the next module read (File formats, 16.2). A reference to a path that is not in artifacts stays as it is.

A file a module wrote into a folder of the person does not count as a result of the run.

Input files come to a module as the references artifact_handles: first the artifacts of the packet, then the field file of each reference to a file in the data of the step — pictures from a variable, an answer to a question, a frame of the previous module. Those of them whose files lie among the results of this run or in the files of the process (files/<name>) also come in artifact_files: { artifact_handle, path }. So a module reads a result file of another module and a file a variable holds. Such a file is read-only: writing into it ends with a refusal of the system (The program: graph and runs, 24.4); a new file the module makes in the work folder and names in artifacts. In the SDK the path to the file of a reference is given by file_path(params, reference): the reference is the object of a reference to a file or its field file; None — there is no file.

A refusal the module gives as a JSON-RPC error with the fields message, data.error_code and data.retryable; a refusal without retryable is not repeated. The codes of the contract of a module — module_failed, module_cancelled and module_not_ready — the function of modules passes on as they are. Any other code is a cause of the module itself: the step ends with module_failed, the code of the module comes in data.module_error_code, and if both dictionaries of the module have the text module.<id>.error.<code> (Modules, table 2), its key comes in data.message_key. A module cannot name a code of the platform: named by the module, it too becomes a cause of the module. In the SDK the cause of the module is named by the field code of a refusal: Refusal("No face in the picture", code="no_face").

An answer outside the protocol does not count as a success: if an answer has neither result nor error, or both, the result is not an object, the output is not from the manifest, what goes along the output is not an object, or a refusal has no code or message, the step ends with module_process_lost.

1.3 cancel

Parameters: { "execution_id": "exec-1" }. A long module must handle a cancel even if the step is still being carried out. A step module the platform may end.

1.4 ping

The answer is { "status": "pong" }, in the middle of a step too. The health check of a long module and a service: the function of modules asks once every modules.ping_interval_ms and stops one that did not answer within modules.ping_timeout_ms (Modules, section 7).

1.5 configure

Parameters: { "nodes": [{ "node_id", "parameters", "models"? }] }. It comes only to a service — at each of its coming up: when the program is switched on and again when a step brings up an unloaded service — before the first step. nodes — the nodes of its module in the process of the program; parameters — as a step would get them: settings and variables put in, the defaults of the manifest added; models — the paths to the networks they chose, as for a step (1.2). The answer is { "status": "configured" }. A module that does not know the method answers method_not_found, and the service works without it; another refusal — the service does not come up, and switching the program on refuses with its text. In the SDK — run_long(…, on_configure=…): the handler gets the list of nodes.

1.6 suspend

Parameters: {}. It comes before unloading only to a module with suspend: true in its manifest (Modules, section 4). The module saves the memory of each node it served into the folder state_dir of that node and only then answers { "status": "suspended" }; after the answer the function of modules puts the mark of the saved memory to each such node and ends the OS process of the module. A module that could not save its memory answers with a refusal with module_failed: the function of modules ends it the same way, reports that the memory may have been lost, and at the next step the nodes get resumed: false. The SDK answers so itself if saving in the module threw an exception.

The notifications of a module (they have no id): progress with the field ratio from 0 to 1 and, at a module with several steps at once, execution_id; log with the fields level (info, warn or error) and message; partial — a part of the result of a step (execution_id, port, data); signal — a signal to its own program (name, optional key and data); for a service — emit, a packet at an output outside a step (port, data and an optional node_id — one of the nodes the service learned of in configure) (Modules, section 7). A signal of a module brought up without a program — by a test call — is not passed on, and the function of modules reports it. In port a notification names an output of the manifest; a notification with another output or without one is not passed on, and the function of modules reports it with the event function.work_failed. Notifications go into stdout as the same JSON lines. Debugging text must not be written into stdout.

The function of modules passes log and progress to the journal with the events module.log and module.progress (Exchange with the kernel, section 7): into the journal of the run, if the module is in a step. A notification with a level the journal does not know, or with a share outside 0–1, is not passed on, and this is reported. In the SDK they are sent by send_log and send_progress.

The platform does not recognise secrets in parameters, at the input, at the output and in the journal and does not cover them with asterisks.

2 The methods of the function of modules

The methods:

Table 1 — The methods of the function of modules

Method Type Purpose
module.execute command at the first call init, then execute
module.cancel command cancelling execution_id; the answer { status: "cancelling" } comes only when the request to cancel has reached the module, otherwise a refusal with the cause
module.release command run_id: unload the long modules of this run after it — end their OS processes, for a module with suspend: true — after suspend. The modules of other runs, even of the same module, and a module in the middle of a step are not touched; services are unloaded by module.service.stop. Without run_id — invalid_request. The answer is { released }
module.service.start command process_id, module_ids and optionally environments — { module_id: process_id }, in whose environment to bring up a service of a called process: bring up the services of a program being switched on (Modules, sections 4, 5). The answer is { started }
module.service.stop command process_id: unload the services of a program being switched off, with suspend for those that can. The answer is { stopped }
module.install command process_id: gather the requirements of the modules of the process — those named in its modules.lock.json (no lock — no such process: document_not_found), make data/processes/<id>/.venv and install them. A clash of versions — module_environment_conflict. A call with module_id is refused: the environment belongs to the process (Modules, section 5)
module.validate query check a manifest: { ok, id, version, execution_semantics } or module_invalid with data.errors — a line per broken field
module.list query the list of installed modules: id (the name of the module folder), ok, version, digest, bytes and files — how much they weigh and how many files they have, the same that go into the print, name_key and description_key — the keys of the name and description in the dictionary of the module (File formats, section 4), inputs, outputs, parameters, input_policy, retry, execution_semantics (not in the manifest — unknown), parallelism (not in the manifest — 1), process — how long the OS process of the module lives, as the manifest names it (Modules, section 4): by it the window learns a node of a service; gpu_mb — how much video memory the module needs, if the manifest names it (resources.gpu_mb). A module whose manifest breaks the format comes with ok: false, error_code: module_invalid and errors — a line per broken field, as at module.validate; the fields that could be read come as they are. A module whose manifest cannot be read or is not a JSON object comes only with id, ok: false, error_code and errors
module.space query { parts: [{ key, title_key, bytes, clear_method? }] } — the parts of the room and how much each takes on the disk; title_key — the name of the part in the dictionary of the owner, clear_method — the command that takes away what can be restored in this part (called with { part: key }): the environments of processes, the cache of packages (a package an environment holds is counted once, in the cache), the installed modules, the networks
module.space.clear command part: "cache": the cache of packages loses what no environment holds (uv cache prune); no environment breaks, and the next install takes again what is missing
module.create command the template of a module: manifest, main.py, locales, requirements.txt
module.delete command module_id: delete a module from the folder of modules together with its files; { module_id, deleted: true }. A module the lock of some program names is not deleted — module_in_use, and names names the programs; one that is up now — module_in_use too; one not installed — module_not_found. A module lying as a link to a folder elsewhere loses the link, not what it points to
module.model.list query neural networks (Modules, section 11): { dir, dir_windows, found, kinds, models } — the folder of networks as WSL sees it and, if wslpath can say, as Windows sees it (otherwise null); found — whether it is there; kinds — the kinds { kind, modules } with the modules that take them: the kinds of installed modules, whose subfolders the function makes when reading, and the subfolders there are; a network has id (<kind>/<name>), kind, name — the name of the file or folder, size — the bytes of the file or of the files of the folder without links inside, folder — whether it is a folder, linked — whether it lies as a link, changed — when it changed, modules — the installed modules that take it by default
module.model.delete command kind, name: delete the file of a network or its folder together with its files, and a link — without what it points to; { kind, name, deleted: true }. A network an installed module takes by default — model_in_use with data.names — the modules; no such network — model_not_found
module.model.take command from, kind, name: put a file or folder from downloads/ of the data folder into the folder of networks as <kind>/<name> — by moving, and between disks by copying with deletion; { kind, name, size }. A path not from downloads/ — path_outside_root; a network with such a name is already there — model_exists: the existing one is not replaced
module.model.needs query process_id: which networks the modules of the program take by default — those named in its modules.lock.json: { needs: [{ module_id, parameter, kind, name, present, sources }] }, sources — where to take it from, as the manifest named it (File formats, section 4)
module.hardware query what this computer has: { gpus: [{ name, memory_mb, free_mb }], memory_mb, free_memory_mb, cores, models_free_mb } — video cards by nvidia-smi (if there is none — an empty list), memory and cores as WSL sees them, free room on the disk of the folder of networks. Writes nothing
module.networks query the networks of the assistant that come ready with OGAS SDK (sdk/networks): { networks: [{ id, version, name_key, description_key, process, parameters, installed }] }, installed — whether the network lies in the folder of modules
module.network.add command module_id: put a ready network of the assistant into the folder of modules; without its .env. Already there — module_exists, no such ready one — module_not_found. The answer is { module_id, added: true }
module.secret.set command module_id, name, value: a line NAME=value in .env of the module folder, the file with mode 0600; an empty value removes the line. The name is capital letters, digits and _, the value one line, otherwise secret_invalid. The answer is { module_id, name, set }, with no value in it
module.secret.names query module_id: { module_id, names } — which secrets of the module are set; the platform does not read or give out the values
module.file.write command module_id, path, text: write a text file of a module whole; the path is simple, inside the module folder, without parts beginning with a dot (not .env, not .venv), no longer than 200 signs, the text no more than 512 KiB, otherwise module_file_refused. The answer is { module_id, path, bytes }
module.file.read query module_id, path: the text of a file of a module by the same rules of the path; { module_id, path, text }
module.test command a test execute without a run: module_id, input, params
module.lock.sync command process_id, module_ids: write modules.lock.json of the process. The version and print of each module the function takes from the installed module; a module that is not installed is not written (Modules, section 3)
module.lock.get query read the recorded versions of the modules of a process
module.state.list query process_id — { process_id, states }: each saved memory has memory (the identifier of a node or the name of a shared memory), the module_id of the module that saved it, bytes and files of the folder, saved — the mark of the saved memory (version, digest, saved_at) or null, up — whether a module that is up serves it now (File formats, 5.3)
module.state.clear command process_id, memory or a list memories — remove the memory folders and marks: their nodes will begin anew; { process_id, cleared }. A memory served by a module that is up — module_state_in_use, and then nothing is cleared. The function of the graph calls the method itself for a memory that no node names after the process is saved
module.state.export command process_id, target — put into the folder of the pack target/<name>/ the saved memory of the process together with the marks; a memory without a mark and a memory served by a module that is up are not put; { states, left_out } — the names of the memories
module.state.import command process_id, source, memories — make the memory from the pack the memory with the same names in the process, together with the marks; { process_id, states }
module.lock.import command process_id, lock — the document ogas.modules-lock/1 from an export: write the versions and prints as they are, not by the installed modules, so that a mismatch with the installed one gives module_version_mismatch when the program is switched on; the generation begins anew. A document of another format or a record of a module without id and version — document_invalid, nothing is written
module.export command module_ids, target (a folder from the data root): copy the files of modules into target/<module_id>/; the answer is modules with the id, version, print, number of files, bytes and links_left_out
module.import command modules and source (an export folder): copy the modules that are not in the installation; an installed one is not overwritten but goes into skipped. A link in the pack — module_invalid, the print of the copy did not match — module_changed. Without source the modules come with their files inside the request
module.inspect query source, module_ids: what an export will bring — { id, version, runtime, names, files, bytes, downloads, digest, links, installed }, where names — the name and description from the dictionaries of the module, downloads — the lines of requirements.txt, installed — absent | same | different

The parameters of module.execute:

How a step goes:

If there are dependencies in requirements.txt and no environment, module_needs_environment comes: the platform does not install anything automatically. When the version of the module does not match the one written in the process — module_version_mismatch.