diff --git a/.changeset/sequence-embeddings-resource-formulas.md b/.changeset/sequence-embeddings-resource-formulas.md new file mode 100644 index 0000000..8194e94 --- /dev/null +++ b/.changeset/sequence-embeddings-resource-formulas.md @@ -0,0 +1,16 @@ +--- +"@platforma-open/milaboratories.sequence-embeddings.software": minor +"@platforma-open/milaboratories.sequence-embeddings.workflow": patch +"@platforma-open/milaboratories.sequence-embeddings.model": patch +"@platforma-open/milaboratories.sequence-embeddings.ui": patch +"@platforma-open/milaboratories.sequence-embeddings": minor +--- + +Optimize embedding compute-resource requests via the fluent `exec.formula` API (workflow-tengo 6.7.x) and size the GPU batch from the allocated VRAM. + +- **Workflow** — the embedding exec now declares resources with `.resources({ onCPU | onGPU })` instead of a flat 16 CPU / 32 GiB / 16 GiB-VRAM request: + - GPU path: host CPU/RAM cut to 2 cores / 8 GiB (single streaming process; the accelerator does the work, per-chunk CPU work is interleaved, and the heavy PColumn→TSV shaping is already upstream CPU execs), and VRAM is model-tiered — 6 GiB for the wider checkpoints (ESM-2 650M, CurrAb, PeptideCLM-2), 3 GiB otherwise. This fits the cheapest fractional-L4 tiers (gpu-3g `g6f.xlarge` / gpu-6g `g6f.2xlarge`) instead of forcing the 4×L40S `g6e.12xlarge` the old 16 CPU / 32 GiB / 16 GiB-VRAM request required. + - CPU path: cores scale with the batch's token volume (`size("batch")`, 4–16) and RAM tracks the core count (2 GiB/core, 8–32 GiB), with a `.staticFallback` equal to the old fixed 16 / 32 GiB for backends that cannot evaluate resource formulas. Advanced-settings overrides still win per dimension. + - The run-report counting pass now sizes its RAM from the source-TSV size (it full-loads the TSV), replacing the flat 4 GiB that could OOM on large inputs. +- **Software** — on CUDA the per-forward token budget is now auto-sized from the allocated VRAM (`PLATFORMA_GPU_MEMORY`), mirroring how `--max-memory-gb` sizes the host-RAM path: a larger VRAM request yields larger batches (higher throughput), a smaller one stays safe. An explicit `--token-budget` still wins, and the halve-on-OOM retry remains the backstop. +- **Model / UI** — the `mem` / `cpu` Advanced-Settings fields are now opt-in: a new block leaves them unset so the workflow's automatic sizing applies, and a user value overrides it per dimension. (Existing projects keep any value they already had.) diff --git a/model/src/dataModel.ts b/model/src/dataModel.ts index 0da420c..81bb754 100644 --- a/model/src/dataModel.ts +++ b/model/src/dataModel.ts @@ -53,7 +53,7 @@ export const blockDataModel = new DataModelBuilder() // The selection is seeded by the UI on first input connection (specialist-first); // starts blank so the dropdowns have an object to bind to before an input exists. embedding: {}, - // Resource defaults for the embedding step (Advanced Settings). - mem: 32, - cpu: 16, + // mem/cpu are intentionally left UNSET: the workflow sizes the embedding step's + // resources automatically from device (CPU/GPU) and input volume. They become + // opt-in overrides — set only when the user fills them in Advanced Settings. })); diff --git a/model/src/types.ts b/model/src/types.ts index 78e61c8..914d099 100644 --- a/model/src/types.ts +++ b/model/src/types.ts @@ -206,8 +206,8 @@ export type BlockDataV1 = { scopesInitializedForAnchor?: string; /** * Advanced — host resources for the embedding step (Resource Allocation in - * Advanced Settings). `mem` is GiB, `cpu` is cores. Undefined → workflow - * defaults (32 GiB / 16 cores). + * Advanced Settings). `mem` is GiB, `cpu` is cores. Undefined → workflow sizes + * automatically from device (CPU/GPU) and input volume. */ mem?: number; cpu?: number; @@ -227,7 +227,7 @@ export type BlockDataV2 = { * Init-guard: canonical id of the anchor whose default cards were last seeded. */ embeddingsInitializedForAnchor?: string; - /** Advanced resource overrides (GiB / cores); undefined → workflow defaults. */ + /** Advanced resource overrides (GiB / cores); undefined → workflow sizes automatically from device + input. */ mem?: number; cpu?: number; defaultBlockLabel?: string; @@ -249,7 +249,7 @@ export type BlockDataV3 = { * input change. */ embeddingInitializedForAnchor?: string; - /** Advanced resource overrides (GiB / cores); undefined → workflow defaults. */ + /** Advanced resource overrides (GiB / cores); undefined → workflow sizes automatically from device + input. */ mem?: number; cpu?: number; defaultBlockLabel?: string; @@ -279,7 +279,7 @@ export type BlockArgs = { inputAnchor: PlRef; /** Tasks to emit — a 1-element list projected from `data.embedding` (validated complete + compatible). */ embeddings: EmbeddingTask[]; - /** Advanced resource overrides for the embedding step (GiB / cores); undefined → workflow defaults. */ + /** Advanced resource overrides for the embedding step (GiB / cores); undefined → workflow sizes automatically. */ mem?: number; cpu?: number; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8954d57..a06b761 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,26 +22,26 @@ catalogs: specifier: 1.10.7 version: 1.10.7 '@platforma-sdk/block-tools': - specifier: 2.11.10 - version: 2.11.10 + specifier: 2.12.7 + version: 2.12.7 '@platforma-sdk/model': - specifier: 1.79.27 - version: 1.79.27 + specifier: 1.80.2 + version: 1.80.2 '@platforma-sdk/package-builder': - specifier: 3.14.0 - version: 3.14.0 + specifier: 3.14.1 + version: 3.14.1 '@platforma-sdk/tengo-builder': - specifier: 4.0.15 - version: 4.0.15 + specifier: 4.0.18 + version: 4.0.18 '@platforma-sdk/test': - specifier: 1.79.28 - version: 1.79.28 + specifier: 1.80.5 + version: 1.80.5 '@platforma-sdk/ui-vue': - specifier: 1.79.27 - version: 1.79.27 + specifier: 1.80.4 + version: 1.80.4 '@platforma-sdk/workflow-tengo': - specifier: 6.6.5 - version: 6.6.5 + specifier: 6.7.2 + version: 6.7.2 ag-grid-enterprise: specifier: ~34.1.2 version: 34.1.2 @@ -83,7 +83,7 @@ importers: version: 1.6.0(@types/node@25.9.1)(esbuild@0.27.7)(rollup@4.61.0)(vue@3.5.35(typescript@6.0.3))(yaml@2.9.0) '@platforma-sdk/block-tools': specifier: 'catalog:' - version: 2.11.10(@types/node@25.9.1) + version: 2.12.7(@types/node@25.9.1) shx: specifier: 'catalog:' version: 0.4.0 @@ -110,10 +110,10 @@ importers: version: link:../workflow '@platforma-sdk/block-tools': specifier: 'catalog:' - version: 2.11.10(@types/node@25.9.1) + version: 2.12.7(@types/node@25.9.1) '@platforma-sdk/model': specifier: 'catalog:' - version: 1.79.27 + version: 1.80.2 shx: specifier: 'catalog:' version: 0.4.0 @@ -125,7 +125,7 @@ importers: dependencies: '@platforma-sdk/model': specifier: 'catalog:' - version: 1.79.27 + version: 1.80.2 '@types/node': specifier: '*' version: 25.9.1 @@ -141,7 +141,7 @@ importers: version: 1.3.0 '@platforma-sdk/block-tools': specifier: 'catalog:' - version: 2.11.10(@types/node@25.9.1) + version: 2.12.7(@types/node@25.9.1) software: devDependencies: @@ -150,7 +150,7 @@ importers: version: 1.10.7 '@platforma-sdk/package-builder': specifier: 'catalog:' - version: 3.14.0 + version: 3.14.1 test: dependencies: @@ -169,7 +169,7 @@ importers: version: 1.3.0 '@platforma-sdk/test': specifier: 'catalog:' - version: 1.79.28(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1)(vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(yaml@2.9.0)) + version: 1.80.5(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1)(vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(yaml@2.9.0)) vitest: specifier: 'catalog:' version: 4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(yaml@2.9.0) @@ -181,10 +181,10 @@ importers: version: link:../model '@platforma-sdk/model': specifier: 'catalog:' - version: 1.79.27 + version: 1.80.2 '@platforma-sdk/ui-vue': specifier: 'catalog:' - version: 1.79.27(@bytecodealliance/preview2-shim@0.17.9)(@vue/compiler-dom@3.5.35)(@vue/server-renderer@3.5.35(vue@3.5.24(typescript@6.0.3)))(typescript@6.0.3) + version: 1.80.4(@bytecodealliance/preview2-shim@0.17.9)(@vue/compiler-dom@3.5.35)(@vue/server-renderer@3.5.35(vue@3.5.24(typescript@6.0.3)))(typescript@6.0.3) '@types/node': specifier: '*' version: 25.9.1 @@ -218,14 +218,14 @@ importers: version: link:../software '@platforma-sdk/workflow-tengo': specifier: 'catalog:' - version: 6.6.5 + version: 6.7.2 devDependencies: '@platforma-sdk/tengo-builder': specifier: 'catalog:' - version: 4.0.15 + version: 4.0.18 '@platforma-sdk/test': specifier: 'catalog:' - version: 1.79.28(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.27.7)(yaml@2.9.0)) + version: 1.80.5(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.27.7)(yaml@2.9.0)) shx: specifier: 'catalog:' version: 0.4.0 @@ -313,6 +313,10 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + '@aws-sdk/client-ecr-public@3.859.0': + resolution: {integrity: sha512-pPY85lrGBNWynofNC6Er49W6aA4JvOOKC9RDbS8rWR8pBPEG6p0B82VQKFMR+3JYRogpfQf5hzU47um96EslFA==} + engines: {node: '>=18.0.0'} + '@aws-sdk/client-s3@3.859.0': resolution: {integrity: sha512-oFLHZX1X6o54ZlweubtSVvQDz15JiNrgDD7KeMZT2MwxiI3axPcHzTo2uizjj5mgNapmYjRmQS5c1c63dvruVA==} engines: {node: '>=18.0.0'} @@ -997,95 +1001,98 @@ packages: '@microsoft/tsdoc@0.16.0': resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} - '@milaboratories/computable@2.9.6': - resolution: {integrity: sha512-Au+84jboSJMM2k39mWUFCtPl2wkislD1fLbb45du1PcAg1GSER1ThSLoBpZUQC2oiTt804WmbzhZ2yaoVZiVLQ==} + '@milaboratories/columns-collection-driver@0.2.1': + resolution: {integrity: sha512-CYdDAhmB01jYq0IXJmbMbA/yTfqSkzwRs0ZJxoSvnzvlu1doc63VIXSvhHOw9b70usR5EFVprR2PvPMTRnjeQQ==} + + '@milaboratories/computable@2.9.7': + resolution: {integrity: sha512-uCMretdt4okbKWkU0aZ0+NHH3hN0wzi2ZIkAvwqha0ZTxUqKilDOlZNAL6QLbmT/7vQs9geAj4amlwSgzkMoww==} engines: {node: '>=22.19.0'} '@milaboratories/helpers@1.14.2': resolution: {integrity: sha512-zOkD4aWNbembwI+AsPTz7nmWC1VPA4rwGBc+Nd5jPpKVh7rCtZwQrlOP5mVqRVMKIAjb1nU8kzzCGfqNPqfJjA==} engines: {node: '>=22'} - '@milaboratories/helpers@1.14.3': - resolution: {integrity: sha512-nZv+n+orVzA/GimDTNj6Yjb52+Wu5f/Kf2z6UCGXni6KTquLBfQhi3AFB1mLE7hkUYPvKU6LxuRY02CQMQiTVA==} + '@milaboratories/helpers@1.14.4': + resolution: {integrity: sha512-0mS5GQAQYUab0qj1C6+IXafNJhL1ahnhPBmIkLq9VqJU8p9jNZ7KC5ln4/pl0tK47brdPljCLEiLg8IdSa6wFw==} engines: {node: '>=22'} - '@milaboratories/pf-driver@1.7.16': - resolution: {integrity: sha512-yujIUylT11CwM4alKVETxTnXQpcKHH1x5hZIAKTni/Q98JHs+teewNhUwpaWACwjuEhmF3EYSTgTXeUoeI9hAg==} + '@milaboratories/pf-driver@1.8.2': + resolution: {integrity: sha512-K5jKzqFfsOJL051U1VAg2Iy9iE01Hwm+FtRb2/PcB0DV3VItIozXRF/mvcXKDHbSCLcPcRGqZjtEF3kMczd+sA==} engines: {node: '>=22.19.0'} - '@milaboratories/pf-spec-driver@1.4.18': - resolution: {integrity: sha512-lXaoSyGCWUlrYZaoyRIWWT0Hpx9DWODXI7VdraNjYnCofJpYKMdAZW3sfCE9kdVup8ic29vywNPLeTjrVQ24sg==} + '@milaboratories/pf-spec-driver@1.4.21': + resolution: {integrity: sha512-JuYVQKs4aia8DA8MVqdImu+Ho+uTwwOqIaJ3VVPMpCMo3QAH9jZP+wGlkklSwow4d+27Y8L2RJN/1dcPr56GZw==} - '@milaboratories/pframes-rs-node@1.1.52': - resolution: {integrity: sha512-Uu4KsQx0GiKvFASI+Cm0nMCMieUVo35mpz4j8mYUYImr7S+bVDDcHweCWrkLkSeImnOQnYHVo9RycViG6QwUQw==} + '@milaboratories/pframes-rs-node@1.1.55': + resolution: {integrity: sha512-TbudDPMixADLyVr5UsiXhf+zq7YCJA3osFrzDn7Lr5aeyorCjiXDkVOGKpID7GkkssuVsNpPXtoGdA71Y2tLjQ==} - '@milaboratories/pframes-rs-serv@1.1.52': - resolution: {integrity: sha512-yVfcyLztgj5UAffj30se5G4MwxkIOFVWPHY1tZZ8zLhQQzx95R/e1toAqq3FLV7y6kpJovwmLusbefgKw9Ejcg==} + '@milaboratories/pframes-rs-serv@1.1.55': + resolution: {integrity: sha512-cGByUULBA/JiwyFEBZrVNOEbnbrMPWWHCWLprRKlVWlmDMaRmsVft/tFpnle46BhDZWpoWbaKEZ8NGOtGqDCXw==} hasBin: true - '@milaboratories/pframes-rs-wasip2@1.1.52': - resolution: {integrity: sha512-0rb0We6Q/aqrHJ062dayvLb4RExODZdqfsVWdzeHq23alY5TjJRMWsO9aKQpPnOuUKjAimdjlp+Ldq9TVhbEtg==} + '@milaboratories/pframes-rs-wasip2@1.1.55': + resolution: {integrity: sha512-mwKTmcDiuN6Id2h+oxKX2W5igFhMxDvRZs4clsxhPTYZASSROrvsSsaoXS81meqfC0phx+BUaRpdrkVQIKSdxQ==} - '@milaboratories/pframes-rs-wasm@1.1.52': - resolution: {integrity: sha512-Wn8/LJxcsvWSSpdymdebWrBnmgu9wAbzvOiHCtXz7Aqt1M2T8Xp9a7CprzCYx+EvhSuAuoxbq6naxkPsQrbkvg==} + '@milaboratories/pframes-rs-wasm@1.1.55': + resolution: {integrity: sha512-kVOL+eAasfeiui5lQ5G92nsSiTNSsOnl1m+4my0tmbR7VTCa15dn1kd5RcXS3/8YO5oEcnGlCUhnu5kKMtweEw==} peerDependencies: '@bytecodealliance/preview2-shim': 0.17.9 '@milaboratories/pl-model-common': 1.46.2 '@milaboratories/pl-model-middle-layer': 1.30.7 - '@milaboratories/pl-client@3.13.2': - resolution: {integrity: sha512-5sx6ehEPfo7q4ojyXgPgQIzn4iPZs7YPvEPctRkwQ6cuK5KzLO059FjzUjsJDh5Si7QbUL/yi5qxCf1h1q4G6g==} + '@milaboratories/pl-client@3.14.2': + resolution: {integrity: sha512-+0ih1njQn4wvLjGmFKboKFRlWYLrzg7QdRK2aNo8ivTKY16TrsMRCk0GQEt0aPKELnv7QSrsNSjg7e7GSdGMDQ==} engines: {node: '>=22.19.0'} - '@milaboratories/pl-config@1.8.3': - resolution: {integrity: sha512-JPIWG/9q7SL9QSYUhHwF9MCfGbpJyo2KxaO9IE2gEvy+oiGw1oBJvNdthC9V/uW2jHp/Qov9+x7LveHzN+bfeA==} + '@milaboratories/pl-config@1.8.4': + resolution: {integrity: sha512-eBZCIVhl9jRigyJUPURCxH2f2OrU5aToihSrwmTkCOu2rjr1spe4YGMIh9CxPr8Z1GkfQbez3crJGME1+RZrrg==} - '@milaboratories/pl-deployments@3.0.10': - resolution: {integrity: sha512-AEFI5gRH1quEUZPqV4wkYabVevpTRGMJXPILsYGh/In9eSw56aHIl8pHoZP5h8v3J5v//KNU7aP8sYANh8S7rA==} + '@milaboratories/pl-deployments@3.0.12': + resolution: {integrity: sha512-Oo7MGAwMyC8F5zCZWgs3Q/sET584Ussux8YP6TB+UBfWcNwZVZWbiO/QaRewfjnMfKSJ4Uden7RoQ4hHWvWChA==} engines: {node: '>=22.19.0'} - '@milaboratories/pl-drivers@1.16.7': - resolution: {integrity: sha512-tEPv4pWekRa5W9zCX0jK6G5lxtXq5f3FVupszxGgkfeQ9op1p3qI8WA4nin52yskKmwPht0R69K97S6tOc2aSg==} + '@milaboratories/pl-drivers@1.16.10': + resolution: {integrity: sha512-5lrewLkmN9Z6dWkRw2kYbsjquHNSHBni8seTI3BsP9xijuv4NzEkvDcJLJsQsuZcuaFtyw77fHAKvNmlYZiJeA==} engines: {node: '>=22'} '@milaboratories/pl-error-like@1.12.10': resolution: {integrity: sha512-iHmnLG5lxJqcymUmEL8onCDGEADk1S/5RNACQ5yfTCNcCkUc+7hYrDHQpFmWXPPGC9sG+NTBxt4wr5m8UsLm2g==} - '@milaboratories/pl-errors@1.4.28': - resolution: {integrity: sha512-wK/mbJSvGv1aCBCXR9YWXICjWBbWAzyAIAQgGtg3PAIJyONdSOCmV8VFUTMjatYEL/38k/0rUePP8MeYwSVm/g==} + '@milaboratories/pl-errors@1.4.31': + resolution: {integrity: sha512-XK4npZNtHksD+IHuzsaf4SXtceqRpwCH/PxZy7zijFqNuW5cdl7be8Parr8T+wQzYaDgHLVSKrYilzC56RNx/Q==} - '@milaboratories/pl-healthcheck@1.0.2': - resolution: {integrity: sha512-IBXQOSgJj7T/dw26AXBsR1ZaOpoqxZtSFZVPE2TonT0VaLKH4XqMFa3C+fKV1aECqbI45dBRQl/X70CUdGPWgQ==} + '@milaboratories/pl-healthcheck@1.0.3': + resolution: {integrity: sha512-krt75tuov2T0TKAsybbSzwHt45JjAQJbnqya0FiRApme913k6DvoowEX2NYLzRChbn+QVbs4ODxJI8lcgFexVg==} engines: {node: '>=22.19.0'} '@milaboratories/pl-http@1.2.4': resolution: {integrity: sha512-QKmhx+WEvJCV9dUy/SBdQk/ApaJ5ewBFgm/b+XPlS10SusAdqUUTGvK5+hq8YSuUMXlHb/dk++UtI5YlDuDl2Q==} - '@milaboratories/pl-middle-layer@1.65.3': - resolution: {integrity: sha512-cLUOlwyGSQzh1uEh2g3bLxhIDvikMn6ymUegHDZdcEt8Dvvy9kFZnZLfF8MRVGIEJtL/aIumPepaHSlfagTk/A==} + '@milaboratories/pl-middle-layer@1.66.4': + resolution: {integrity: sha512-rFyxoWpFNjA5FPU6A5Usf0FyDx+XzFSsDqsPRf3NVuxrk6No6cNGZVUerdpXZJ6qCEsJwdgMBRECyBI5MV5bRw==} engines: {node: '>=22.19.0'} - '@milaboratories/pl-model-backend@1.4.13': - resolution: {integrity: sha512-HGEVDZXh/XUU5sDuBB46pMc1+46elzvrPuKCaowhqpzBPzA4j/DNxuJucJRv/h/oE0Ue3kEQf+6x0506kGDrow==} + '@milaboratories/pl-model-backend@1.4.16': + resolution: {integrity: sha512-MrJwM3aOzrqr3+GVpS/1Zh/SOH/2tBtoyk/+eE6C7LRjofoip8GIF4be8AgPAM3C+6wTSGrQ5x3CM6A8Ql2HVA==} '@milaboratories/pl-model-common@1.46.2': resolution: {integrity: sha512-VEeauisApYScvCS8lnK3zpFJ520xuTAodKJmjR8ulHcMrWMyWMfHEdGb7j5OMD0mM/OwTgmQrrJ5eB7Xd+xoOQ==} - '@milaboratories/pl-model-common@1.46.4': - resolution: {integrity: sha512-QArgLyQkf8kHSQquxStyk5Xfnau8S4M2vKEbUVQRRoZCzLU1lcDVXRwGgAzRH5NizeqYNrB/wt0/tShajH+6eA==} + '@milaboratories/pl-model-common@1.47.1': + resolution: {integrity: sha512-5F9I8JvUPRJ2HEzz5MmTio6JFYnhYoMVHfToh2NyXyOyQgAF6jhOzZBOsrEig9NfCPZBRB7v6UjmIK43dG4o/g==} - '@milaboratories/pl-model-middle-layer@1.30.11': - resolution: {integrity: sha512-yFThwVqOTb2gJw/tp4PkZcsKI7yRRJCX3QuA6fIc2+tNxCqyEQmdpLmaIY/nhaziIp9ByBT9MrzWNIQd1T9aww==} + '@milaboratories/pl-model-middle-layer@1.30.13': + resolution: {integrity: sha512-owQVozyub/6aKgk+yce+9sDK+t0HrpLbnlKJqQjYJahuhoju8j6VMY17AWgvADSDCiI3gnp/Tm/I4Ur6ySs1Cg==} '@milaboratories/pl-model-middle-layer@1.30.7': resolution: {integrity: sha512-rs9x3Ron4ujR/UOdEgB8WUB1SvZ8ZAScT1Av/e4or+iiQ/CzhmK9nqtYamHVwKV+JgwIFbXQwxGvIHDVz955dQ==} - '@milaboratories/pl-tree@1.12.18': - resolution: {integrity: sha512-2vx0JNFDQklz23JMK8s+34LrhFqY0zDDLTLDCOdWgrlNKbd6mr956fKxmvIBML4++Ngs8Izs45B0PNGwhkEBrw==} + '@milaboratories/pl-tree@1.13.1': + resolution: {integrity: sha512-NtVVUSF9eJA5v5iUEfGgKl0JbG/EIvy+YCsxzCZ1dXG1S3gCNwt01Nj5PkWW7FkDG1IT0ZfwyeO0mVVz2kIv1Q==} engines: {node: '>=22.19.0'} - '@milaboratories/ptabler-expression-js@1.2.33': - resolution: {integrity: sha512-ThB7tc0nPACE7b8cSoA0+zRVZfZHOCAcFioFDi207G5prgrIc/z2zbInjD0PRnWFHO7xOsfbWCkNRDqCmut6zQ==} + '@milaboratories/ptabler-expression-js@1.2.35': + resolution: {integrity: sha512-nTVNYgNHuUswPnAe8GFAitbewNVMHaxhAncQ3yMYfGzsGgZupQyGV6K1DHVkzMAwNwVFVLwIbiPMY58en03XWQ==} '@milaboratories/resolve-helper@1.1.3': resolution: {integrity: sha512-38/dW/XRZQREOxAOOKtO0lzEWPCP/DH0qhB3q1kYcGoN++5V92/zbVwbYrMDeDcjTyo+D62iIep+sKXeWHa7Uw==} @@ -1105,12 +1112,12 @@ packages: '@milaboratories/ts-configs@1.3.0': resolution: {integrity: sha512-6rZaMOJotG+v6eXoupHgPqxArpNBNl0f7sd5K+kUo1PUhPTe632eLJtEeBbFtwDGNYqL9QUacd4pT5t6oDOf0A==} - '@milaboratories/ts-helpers@1.8.4': - resolution: {integrity: sha512-YdOyANkJjFiEZgS3bfbludDo9PWOQZQ8AhGw/rpO5/7bgQ9RIVOOTAtP5/UppANoeUiYhCgJt/xvIZgnQ/PZ0w==} + '@milaboratories/ts-helpers@1.8.5': + resolution: {integrity: sha512-vZDcIBta7I935VjKk6qGdhpjz2pWXe5CbWv1UUmPrcG8wsunDpWuet8/Gi75N97CpcLDc2LLHd/url9K8ZNpAg==} engines: {node: '>=22.19.0'} - '@milaboratories/uikit@2.15.13': - resolution: {integrity: sha512-IdPV9xuwULSx0zXc006dzfOatJBHJ39TmsBnkdsQ235Jz+c++Klpp8tBvDjeXO10nv0xQiIRTXvDCeXebrRTOg==} + '@milaboratories/uikit@2.15.16': + resolution: {integrity: sha512-HOl1YsPKHpj3izKAs0hEvVtFE8ZbrOnD5KsAqSHxvipQyfAdOLbfB7ak6XPdPKbgsvH5opfMws7usryR6Nlulw==} '@napi-rs/wasm-runtime@1.1.6': resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} @@ -1704,14 +1711,14 @@ packages: '@platforma-open/milaboratories.runenv-python-3@1.10.7': resolution: {integrity: sha512-Rc6iBMfzMh9/kAC44Rv2sQY5svk8K95ty7SdGdEYMlftZBT2rzboc1LP1UcQtWN3ndU2i4Giu+QbKs0MwjHUWQ==} - '@platforma-open/milaboratories.software-ptabler.schema@1.15.17': - resolution: {integrity: sha512-Qf4QpFY8bWVtEeQphWGZ67dUaXYVWSFm/AL1ErzdOYhilnDSon2Cya6K2Fkj0TxEGBLMBxOudF/kmTw728/Pag==} + '@platforma-open/milaboratories.software-ptabler.schema@1.15.19': + resolution: {integrity: sha512-h/FBLELZT6PJZnWtwvcy8bQrpZ2A6xWSVSjyccqb3QolHSbeuwi5UpUph8UxdDYNmWSCH0zR/zE2hFypgk21xA==} - '@platforma-open/milaboratories.software-ptabler@2.1.3': - resolution: {integrity: sha512-4cikdkdJ5WYc0Nw3IoZxzlFNKvG1qCAqSjypq5b18pIK6LBDayzhFcuw5TDd8O3bAFhoHP+3cVTmoO9XUTYMRg==} + '@platforma-open/milaboratories.software-ptabler@2.1.6': + resolution: {integrity: sha512-LdDU9/z+iejw5F98J8DYVQKsjUGGiyu8rHWCjWCEqOVEP+N9QBcN4ibDgG4Xp/GL+IzKxicAkf2Ae9lHollD6w==} - '@platforma-open/milaboratories.software-ptexter@1.2.2': - resolution: {integrity: sha512-I08YpKQ4+esLrfpVra5UJ+bznI9Zzba6OW0rKK407a1EUmanvYMVrCbM9gqnm6CHbv2vQxNGSaO8p1LoBh+9gA==} + '@platforma-open/milaboratories.software-ptexter@1.2.3': + resolution: {integrity: sha512-5wwzvPko/tjkm6EnirsnjB+MO5mF//tgJplI+jPh3bcSHpEdHF+B9xg+S1owAnekqbimMrFZWqHSVY9ZmIHOjw==} '@platforma-open/milaboratories.software-small-binaries.hello-world-py@1.0.10': resolution: {integrity: sha512-16BGRLIrsVW+YIaXwWLX6Nbm80PS5mQJEclHhjNbRrRTLHPaKI4RygZfBC0lLNzvHBiTXU4Qkh1+WmdovkshDg==} @@ -1731,37 +1738,37 @@ packages: '@platforma-open/milaboratories.software-small-binaries@2.1.1': resolution: {integrity: sha512-KN1PR7YgUUfx1dxh/TtcoWpSZbOXbRxXzQuJ505qHuXuE0spYwC7bXnvJsEYbEwRcPMa0foTrjBnPNORE4yr+Q==} - '@platforma-sdk/block-tools@2.11.10': - resolution: {integrity: sha512-HpPLzw/HIrkXPJ8fGSrZUwnik11ts4tbL1gidmB2Mw8X3uq3N0SDK4qDeHyMY/sVVXeW6tEnyYciWGCr9f5esg==} + '@platforma-sdk/block-tools@2.12.7': + resolution: {integrity: sha512-a13K0hcXYf+sgx+07QFjIu2uTeTH5lhHHI1o563kvs9Z5vssU9jn7HFgXgSe6TMjDntERJcGHiGm8nUd4t3FiA==} hasBin: true '@platforma-sdk/blocks-deps-updater@2.2.0': resolution: {integrity: sha512-p9lBxhFXM9WoRsrJO7dfkiXSK+1m63yIn1sKhBO71eMbhrLMyVYHEOeNf3w5OCdbRF5QsNhXzWuiTmFK3zHFsA==} hasBin: true - '@platforma-sdk/model@1.79.27': - resolution: {integrity: sha512-Z5WYpClTZoBtvfGsiDPNlRCxPKtUF04TV3MmL1Kfb6xAb04B5NdiqWMnqw+v78Kue/y9FKTmxrCcX9lwZgYFlw==} + '@platforma-sdk/model@1.80.2': + resolution: {integrity: sha512-aQGVxjxw7y34U0ZuboIYASodJMZ1yTjXH2y44bCdeTeS/r81YBBmGrF6BQhHHVjIOIhaIlWHRBIhd9AJo42aWQ==} - '@platforma-sdk/package-builder-lib@1.1.0': - resolution: {integrity: sha512-h/Hx4Fg+kGnX2sVPWJa48JHbSEofTnaOescTKBP1Py5wl3A68BjqKaI6yybLWSR5Ojp3tHNNlvFSAnoF2QYMMg==} + '@platforma-sdk/package-builder-lib@1.2.0': + resolution: {integrity: sha512-AtSzaZ39BGlqcyYtpGREDz+YlGCDdSTQJNV/+NkTyUtoq1ECRO+iMqAX1DSSza1WqylnURX8vKVI2owS/cxntA==} - '@platforma-sdk/package-builder@3.14.0': - resolution: {integrity: sha512-7bRducsc9NLc1zo0GRfz3RHSTejxFfmFvr21EH8NBndGaCj5KvHt2+0jmQsSI1Sl7ZCaj+zQKWWukRlsi+b/uA==} + '@platforma-sdk/package-builder@3.14.1': + resolution: {integrity: sha512-slkVlHMxPuSvMTfWarFuG4AQHUdBehascrgf7xFaQwgOLbjegMg7IH4XzNzb5IEANZUQYSmHUDcIulKQGXNgog==} hasBin: true - '@platforma-sdk/tengo-builder@4.0.15': - resolution: {integrity: sha512-qBWtAD1f1ZFFfkN7mvYKaI2qKbvQ9wHVh5edGTaKMFU5GFEu5IA3RP4SJw4ht69WjXAEu51VOvvPFwRX1P4H3g==} + '@platforma-sdk/tengo-builder@4.0.18': + resolution: {integrity: sha512-nGPB5fE6b9ITFuXVMRakr2MyqsnL4TVE09jZ2X7TCPgb31k4gIhYCT+XU9vBRavBj/U3dt+jSWHkcbX9JvJKYA==} engines: {node: '>=22'} hasBin: true - '@platforma-sdk/test@1.79.28': - resolution: {integrity: sha512-ae/eZMjyhv/m+xg+KoznDWfzFFSPuBKVxVU7orNge10M167xkhrc5fh9pwRJ+HRf2CnWHuUCLEXyfiH8VOnfmA==} + '@platforma-sdk/test@1.80.5': + resolution: {integrity: sha512-z3tBrNWIg0+OfUOKpiZWCFflSW17J/Tv7DRWK99IzaaS0+MrIhC6oEFJGXnDlbynhnhSp3E+a4HiwEe+SG/rCg==} - '@platforma-sdk/ui-vue@1.79.27': - resolution: {integrity: sha512-L88b8A42n4GRGqMHY4n5o+ROwxPBFSgnwr7axjb1k/zfvKRsawz5urxQ8IEPGQW/41UhxNImIiDmdOD17vHtJQ==} + '@platforma-sdk/ui-vue@1.80.4': + resolution: {integrity: sha512-DQbuO3fAJ3CQxiJkXMiNuo1Qyd/C92AatOZX90ElLFohXiP3XbJNXNjrIxypzsUc850dKkqbPjKd0JTzD12E9w==} - '@platforma-sdk/workflow-tengo@6.6.5': - resolution: {integrity: sha512-BIY0DongPruQ7e2EMYy2b0UtO5ziGcLvr2RWgJ8ki17VKNzW3esm/RBszGHMrTYmXM0Yw7mCSasor4vH560g7A==} + '@platforma-sdk/workflow-tengo@6.7.2': + resolution: {integrity: sha512-KJ4tBigEDN+EIDy7K2u7PqxBIDrhwvnazJthApGg2N/HPZkinKmq0iMzHC9KZ0IsJVg6uxECIB2d2Acko33tOw==} '@protobuf-ts/grpc-transport@2.11.1': resolution: {integrity: sha512-l6wrcFffY+tuNnuyrNCkRM8hDIsAZVLA8Mn7PKdVyYxITosYh60qW663p9kL6TWXYuDCL3oxH8ih3vLKTDyhtg==} @@ -4978,6 +4985,50 @@ snapshots: '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 + '@aws-sdk/client-ecr-public@3.859.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.858.0 + '@aws-sdk/credential-provider-node': 3.859.0 + '@aws-sdk/middleware-host-header': 3.840.0 + '@aws-sdk/middleware-logger': 3.840.0 + '@aws-sdk/middleware-recursion-detection': 3.840.0 + '@aws-sdk/middleware-user-agent': 3.858.0 + '@aws-sdk/region-config-resolver': 3.840.0 + '@aws-sdk/types': 3.840.0 + '@aws-sdk/util-endpoints': 3.848.0 + '@aws-sdk/util-user-agent-browser': 3.840.0 + '@aws-sdk/util-user-agent-node': 3.858.0 + '@smithy/config-resolver': 4.5.6 + '@smithy/core': 3.24.6 + '@smithy/fetch-http-handler': 5.4.6 + '@smithy/hash-node': 4.3.6 + '@smithy/invalid-dependency': 4.3.6 + '@smithy/middleware-content-length': 4.3.6 + '@smithy/middleware-endpoint': 4.5.6 + '@smithy/middleware-retry': 4.6.6 + '@smithy/middleware-serde': 4.3.6 + '@smithy/middleware-stack': 4.3.6 + '@smithy/node-config-provider': 4.4.6 + '@smithy/node-http-handler': 4.7.6 + '@smithy/protocol-http': 5.4.6 + '@smithy/smithy-client': 4.13.6 + '@smithy/types': 4.14.3 + '@smithy/url-parser': 4.3.6 + '@smithy/util-base64': 4.4.6 + '@smithy/util-body-length-browser': 4.3.6 + '@smithy/util-body-length-node': 4.3.6 + '@smithy/util-defaults-mode-browser': 4.4.6 + '@smithy/util-defaults-mode-node': 4.3.6 + '@smithy/util-endpoints': 3.5.6 + '@smithy/util-middleware': 4.3.6 + '@smithy/util-retry': 4.4.6 + '@smithy/util-utf8': 4.3.6 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/client-s3@3.859.0': dependencies: '@aws-crypto/sha1-browser': 5.2.0 @@ -6062,25 +6113,30 @@ snapshots: '@microsoft/tsdoc@0.16.0': {} - '@milaboratories/computable@2.9.6': + '@milaboratories/columns-collection-driver@0.2.1': + dependencies: + '@milaboratories/helpers': 1.14.4 + '@milaboratories/pl-model-common': 1.47.1 + + '@milaboratories/computable@2.9.7': dependencies: '@milaboratories/pl-error-like': 1.12.10 - '@milaboratories/ts-helpers': 1.8.4 + '@milaboratories/ts-helpers': 1.8.5 '@types/node': 24.5.2 utility-types: 3.11.0 '@milaboratories/helpers@1.14.2': {} - '@milaboratories/helpers@1.14.3': {} + '@milaboratories/helpers@1.14.4': {} - '@milaboratories/pf-driver@1.7.16(@bytecodealliance/preview2-shim@0.17.9)': + '@milaboratories/pf-driver@1.8.2(@bytecodealliance/preview2-shim@0.17.9)': dependencies: - '@milaboratories/helpers': 1.14.3 - '@milaboratories/pframes-rs-node': 1.1.52 - '@milaboratories/pframes-rs-wasm': 1.1.52(@bytecodealliance/preview2-shim@0.17.9)(@milaboratories/pl-model-common@1.46.4)(@milaboratories/pl-model-middle-layer@1.30.11) - '@milaboratories/pl-model-common': 1.46.4 - '@milaboratories/pl-model-middle-layer': 1.30.11 - '@milaboratories/ts-helpers': 1.8.4 + '@milaboratories/helpers': 1.14.4 + '@milaboratories/pframes-rs-node': 1.1.55 + '@milaboratories/pframes-rs-wasm': 1.1.55(@bytecodealliance/preview2-shim@0.17.9)(@milaboratories/pl-model-common@1.47.1)(@milaboratories/pl-model-middle-layer@1.30.13) + '@milaboratories/pl-model-common': 1.47.1 + '@milaboratories/pl-model-middle-layer': 1.30.13 + '@milaboratories/ts-helpers': 1.8.5 es-toolkit: 1.47.0 lru-cache: 11.5.1 transitivePeerDependencies: @@ -6088,28 +6144,28 @@ snapshots: - encoding - supports-color - '@milaboratories/pf-spec-driver@1.4.18(@bytecodealliance/preview2-shim@0.17.9)': + '@milaboratories/pf-spec-driver@1.4.21(@bytecodealliance/preview2-shim@0.17.9)': dependencies: - '@milaboratories/helpers': 1.14.3 - '@milaboratories/pframes-rs-wasm': 1.1.52(@bytecodealliance/preview2-shim@0.17.9)(@milaboratories/pl-model-common@1.46.4)(@milaboratories/pl-model-middle-layer@1.30.11) - '@milaboratories/pl-model-common': 1.46.4 - '@milaboratories/pl-model-middle-layer': 1.30.11 + '@milaboratories/helpers': 1.14.4 + '@milaboratories/pframes-rs-wasm': 1.1.55(@bytecodealliance/preview2-shim@0.17.9)(@milaboratories/pl-model-common@1.47.1)(@milaboratories/pl-model-middle-layer@1.30.13) + '@milaboratories/pl-model-common': 1.47.1 + '@milaboratories/pl-model-middle-layer': 1.30.13 '@noble/hashes': 2.2.0 transitivePeerDependencies: - '@bytecodealliance/preview2-shim' - '@milaboratories/pframes-rs-node@1.1.52': + '@milaboratories/pframes-rs-node@1.1.55': dependencies: '@mapbox/node-pre-gyp': 2.0.3 '@milaboratories/helpers': 1.14.2 - '@milaboratories/pframes-rs-serv': 1.1.52 + '@milaboratories/pframes-rs-serv': 1.1.55 '@milaboratories/pl-model-common': 1.46.2 ulid: 3.0.2 transitivePeerDependencies: - encoding - supports-color - '@milaboratories/pframes-rs-serv@1.1.52': + '@milaboratories/pframes-rs-serv@1.1.55': dependencies: '@milaboratories/helpers': 1.14.2 '@milaboratories/pl-model-common': 1.46.2 @@ -6118,21 +6174,21 @@ snapshots: commander: 14.0.3 selfsigned: 5.5.0 - '@milaboratories/pframes-rs-wasip2@1.1.52': {} + '@milaboratories/pframes-rs-wasip2@1.1.55': {} - '@milaboratories/pframes-rs-wasm@1.1.52(@bytecodealliance/preview2-shim@0.17.9)(@milaboratories/pl-model-common@1.46.4)(@milaboratories/pl-model-middle-layer@1.30.11)': + '@milaboratories/pframes-rs-wasm@1.1.55(@bytecodealliance/preview2-shim@0.17.9)(@milaboratories/pl-model-common@1.47.1)(@milaboratories/pl-model-middle-layer@1.30.13)': dependencies: '@bytecodealliance/preview2-shim': 0.17.9 - '@milaboratories/pframes-rs-wasip2': 1.1.52 - '@milaboratories/pl-model-common': 1.46.4 - '@milaboratories/pl-model-middle-layer': 1.30.11 + '@milaboratories/pframes-rs-wasip2': 1.1.55 + '@milaboratories/pl-model-common': 1.47.1 + '@milaboratories/pl-model-middle-layer': 1.30.13 - '@milaboratories/pl-client@3.13.2': + '@milaboratories/pl-client@3.14.2': dependencies: '@grpc/grpc-js': 1.13.5 '@milaboratories/pl-http': 1.2.4 - '@milaboratories/pl-model-common': 1.46.4 - '@milaboratories/ts-helpers': 1.8.4 + '@milaboratories/pl-model-common': 1.47.1 + '@milaboratories/ts-helpers': 1.8.5 '@protobuf-ts/grpc-transport': 2.11.1(@grpc/grpc-js@1.13.5) '@protobuf-ts/runtime': 2.11.1 '@protobuf-ts/runtime-rpc': 2.11.1 @@ -6145,19 +6201,19 @@ snapshots: utility-types: 3.11.0 yaml: 2.9.0 - '@milaboratories/pl-config@1.8.3': + '@milaboratories/pl-config@1.8.4': dependencies: - '@milaboratories/ts-helpers': 1.8.4 + '@milaboratories/ts-helpers': 1.8.5 upath: 2.0.1 yaml: 2.9.0 - '@milaboratories/pl-deployments@3.0.10': + '@milaboratories/pl-deployments@3.0.12': dependencies: - '@milaboratories/pl-config': 1.8.3 - '@milaboratories/pl-healthcheck': 1.0.2 + '@milaboratories/pl-config': 1.8.4 + '@milaboratories/pl-healthcheck': 1.0.3 '@milaboratories/pl-http': 1.2.4 - '@milaboratories/pl-model-common': 1.46.4 - '@milaboratories/ts-helpers': 1.8.4 + '@milaboratories/pl-model-common': 1.47.1 + '@milaboratories/ts-helpers': 1.8.5 decompress: 4.2.1 ssh2: 1.17.0 tar: 7.5.16 @@ -6166,15 +6222,15 @@ snapshots: yaml: 2.9.0 zod: 3.25.76 - '@milaboratories/pl-drivers@1.16.7': + '@milaboratories/pl-drivers@1.16.10': dependencies: '@grpc/grpc-js': 1.13.5 - '@milaboratories/computable': 2.9.6 - '@milaboratories/helpers': 1.14.3 - '@milaboratories/pl-client': 3.13.2 - '@milaboratories/pl-model-common': 1.46.4 - '@milaboratories/pl-tree': 1.12.18 - '@milaboratories/ts-helpers': 1.8.4 + '@milaboratories/computable': 2.9.7 + '@milaboratories/helpers': 1.14.4 + '@milaboratories/pl-client': 3.14.2 + '@milaboratories/pl-model-common': 1.47.1 + '@milaboratories/pl-tree': 1.13.1 + '@milaboratories/ts-helpers': 1.8.5 '@protobuf-ts/grpc-transport': 2.11.1(@grpc/grpc-js@1.13.5) '@protobuf-ts/plugin': 2.11.1 '@protobuf-ts/runtime': 2.11.1 @@ -6197,16 +6253,16 @@ snapshots: json-stringify-safe: 5.0.1 zod: 3.25.76 - '@milaboratories/pl-errors@1.4.28': + '@milaboratories/pl-errors@1.4.31': dependencies: - '@milaboratories/pl-client': 3.13.2 - '@milaboratories/ts-helpers': 1.8.4 + '@milaboratories/pl-client': 3.14.2 + '@milaboratories/ts-helpers': 1.8.5 zod: 3.25.76 - '@milaboratories/pl-healthcheck@1.0.2': + '@milaboratories/pl-healthcheck@1.0.3': dependencies: '@grpc/grpc-js': 1.13.5 - '@milaboratories/ts-helpers': 1.8.4 + '@milaboratories/ts-helpers': 1.8.5 '@protobuf-ts/grpc-transport': 2.11.1(@grpc/grpc-js@1.13.5) '@protobuf-ts/runtime': 2.11.1 '@protobuf-ts/runtime-rpc': 2.11.1 @@ -6215,28 +6271,29 @@ snapshots: dependencies: undici: 7.16.0 - '@milaboratories/pl-middle-layer@1.65.3(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1)': - dependencies: - '@milaboratories/computable': 2.9.6 - '@milaboratories/helpers': 1.14.3 - '@milaboratories/pf-driver': 1.7.16(@bytecodealliance/preview2-shim@0.17.9) - '@milaboratories/pf-spec-driver': 1.4.18(@bytecodealliance/preview2-shim@0.17.9) - '@milaboratories/pframes-rs-node': 1.1.52 - '@milaboratories/pframes-rs-wasm': 1.1.52(@bytecodealliance/preview2-shim@0.17.9)(@milaboratories/pl-model-common@1.46.4)(@milaboratories/pl-model-middle-layer@1.30.11) - '@milaboratories/pl-client': 3.13.2 - '@milaboratories/pl-deployments': 3.0.10 - '@milaboratories/pl-drivers': 1.16.7 - '@milaboratories/pl-errors': 1.4.28 + '@milaboratories/pl-middle-layer@1.66.4(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1)': + dependencies: + '@milaboratories/columns-collection-driver': 0.2.1 + '@milaboratories/computable': 2.9.7 + '@milaboratories/helpers': 1.14.4 + '@milaboratories/pf-driver': 1.8.2(@bytecodealliance/preview2-shim@0.17.9) + '@milaboratories/pf-spec-driver': 1.4.21(@bytecodealliance/preview2-shim@0.17.9) + '@milaboratories/pframes-rs-node': 1.1.55 + '@milaboratories/pframes-rs-wasm': 1.1.55(@bytecodealliance/preview2-shim@0.17.9)(@milaboratories/pl-model-common@1.47.1)(@milaboratories/pl-model-middle-layer@1.30.13) + '@milaboratories/pl-client': 3.14.2 + '@milaboratories/pl-deployments': 3.0.12 + '@milaboratories/pl-drivers': 1.16.10 + '@milaboratories/pl-errors': 1.4.31 '@milaboratories/pl-http': 1.2.4 - '@milaboratories/pl-model-backend': 1.4.13 - '@milaboratories/pl-model-common': 1.46.4 - '@milaboratories/pl-model-middle-layer': 1.30.11 - '@milaboratories/pl-tree': 1.12.18 + '@milaboratories/pl-model-backend': 1.4.16 + '@milaboratories/pl-model-common': 1.47.1 + '@milaboratories/pl-model-middle-layer': 1.30.13 + '@milaboratories/pl-tree': 1.13.1 '@milaboratories/resolve-helper': 1.1.3 - '@milaboratories/ts-helpers': 1.8.4 - '@platforma-sdk/block-tools': 2.11.10(@types/node@25.9.1) - '@platforma-sdk/model': 1.79.27 - '@platforma-sdk/workflow-tengo': 6.6.5 + '@milaboratories/ts-helpers': 1.8.5 + '@platforma-sdk/block-tools': 2.12.7(@types/node@25.9.1) + '@platforma-sdk/model': 1.80.2 + '@platforma-sdk/workflow-tengo': 6.7.2 canonicalize: 2.1.0 denque: 2.1.0 es-toolkit: 1.47.0 @@ -6257,9 +6314,9 @@ snapshots: - react-native-b4a - supports-color - '@milaboratories/pl-model-backend@1.4.13': + '@milaboratories/pl-model-backend@1.4.16': dependencies: - '@milaboratories/pl-client': 3.13.2 + '@milaboratories/pl-client': 3.14.2 canonicalize: 2.1.0 zod: 3.25.76 @@ -6270,17 +6327,18 @@ snapshots: canonicalize: 2.1.0 zod: 3.25.76 - '@milaboratories/pl-model-common@1.46.4': + '@milaboratories/pl-model-common@1.47.1': dependencies: - '@milaboratories/helpers': 1.14.3 + '@milaboratories/helpers': 1.14.4 '@milaboratories/pl-error-like': 1.12.10 canonicalize: 2.1.0 + es-toolkit: 1.47.0 zod: 3.25.76 - '@milaboratories/pl-model-middle-layer@1.30.11': + '@milaboratories/pl-model-middle-layer@1.30.13': dependencies: - '@milaboratories/helpers': 1.14.3 - '@milaboratories/pl-model-common': 1.46.4 + '@milaboratories/helpers': 1.14.4 + '@milaboratories/pl-model-common': 1.47.1 es-toolkit: 1.47.0 utility-types: 3.11.0 zod: 3.25.76 @@ -6293,19 +6351,19 @@ snapshots: utility-types: 3.11.0 zod: 3.25.76 - '@milaboratories/pl-tree@1.12.18': + '@milaboratories/pl-tree@1.13.1': dependencies: - '@milaboratories/computable': 2.9.6 - '@milaboratories/pl-client': 3.13.2 - '@milaboratories/pl-errors': 1.4.28 - '@milaboratories/ts-helpers': 1.8.4 + '@milaboratories/computable': 2.9.7 + '@milaboratories/pl-client': 3.14.2 + '@milaboratories/pl-errors': 1.4.31 + '@milaboratories/ts-helpers': 1.8.5 denque: 2.1.0 utility-types: 3.11.0 zod: 3.25.76 - '@milaboratories/ptabler-expression-js@1.2.33': + '@milaboratories/ptabler-expression-js@1.2.35': dependencies: - '@platforma-open/milaboratories.software-ptabler.schema': 1.15.17 + '@platforma-open/milaboratories.software-ptabler.schema': 1.15.19 '@milaboratories/resolve-helper@1.1.3': {} @@ -6438,16 +6496,16 @@ snapshots: '@milaboratories/ts-configs@1.3.0': {} - '@milaboratories/ts-helpers@1.8.4': + '@milaboratories/ts-helpers@1.8.5': dependencies: - '@milaboratories/helpers': 1.14.3 + '@milaboratories/helpers': 1.14.4 canonicalize: 2.1.0 denque: 2.1.0 - '@milaboratories/uikit@2.15.13(@vue/compiler-dom@3.5.35)(@vue/server-renderer@3.5.35(vue@3.5.24(typescript@6.0.3)))(typescript@6.0.3)': + '@milaboratories/uikit@2.15.16(@vue/compiler-dom@3.5.35)(@vue/server-renderer@3.5.35(vue@3.5.24(typescript@6.0.3)))(typescript@6.0.3)': dependencies: - '@milaboratories/helpers': 1.14.3 - '@platforma-sdk/model': 1.79.27 + '@milaboratories/helpers': 1.14.4 + '@platforma-sdk/model': 1.80.2 '@types/d3-array': 3.2.2 '@types/d3-axis': 3.0.6 '@types/d3-scale': 4.0.9 @@ -6901,13 +6959,13 @@ snapshots: '@platforma-open/milaboratories.runenv-python-3.12.10-scientific-slim': 1.1.0 '@platforma-open/milaboratories.runenv-python-3.12.10-torch-cuda': 0.2.0 - '@platforma-open/milaboratories.software-ptabler.schema@1.15.17': + '@platforma-open/milaboratories.software-ptabler.schema@1.15.19': dependencies: - '@milaboratories/pl-model-common': 1.46.4 + '@milaboratories/pl-model-common': 1.47.1 - '@platforma-open/milaboratories.software-ptabler@2.1.3': {} + '@platforma-open/milaboratories.software-ptabler@2.1.6': {} - '@platforma-open/milaboratories.software-ptexter@1.2.2': {} + '@platforma-open/milaboratories.software-ptexter@1.2.3': {} '@platforma-open/milaboratories.software-small-binaries.hello-world-py@1.0.10': {} @@ -6927,17 +6985,19 @@ snapshots: '@platforma-open/milaboratories.software-small-binaries.mnz-client': 1.6.5 '@platforma-open/milaboratories.software-small-binaries.table-converter': 1.3.5 - '@platforma-sdk/block-tools@2.11.10(@types/node@25.9.1)': + '@platforma-sdk/block-tools@2.12.7(@types/node@25.9.1)': dependencies: + '@aws-sdk/client-ecr-public': 3.859.0 '@aws-sdk/client-s3': 3.859.0 '@inquirer/prompts': 7.10.1(@types/node@25.9.1) '@milaboratories/pl-http': 1.2.4 - '@milaboratories/pl-model-backend': 1.4.13 - '@milaboratories/pl-model-common': 1.46.4 - '@milaboratories/pl-model-middle-layer': 1.30.11 + '@milaboratories/pl-model-backend': 1.4.16 + '@milaboratories/pl-model-common': 1.47.1 + '@milaboratories/pl-model-middle-layer': 1.30.13 '@milaboratories/resolve-helper': 1.1.3 - '@milaboratories/ts-helpers': 1.8.4 + '@milaboratories/ts-helpers': 1.8.5 '@platforma-sdk/blocks-deps-updater': 2.2.0 + '@platforma-sdk/package-builder-lib': 1.2.0 canonicalize: 2.1.0 commander: 15.0.0 lru-cache: 11.5.1 @@ -6949,25 +7009,29 @@ snapshots: transitivePeerDependencies: - '@types/node' - aws-crt + - bare-abort-controller + - bare-buffer + - react-native-b4a '@platforma-sdk/blocks-deps-updater@2.2.0': dependencies: yaml: 2.9.0 - '@platforma-sdk/model@1.79.27': + '@platforma-sdk/model@1.80.2': dependencies: - '@milaboratories/helpers': 1.14.3 + '@milaboratories/helpers': 1.14.4 '@milaboratories/pl-error-like': 1.12.10 - '@milaboratories/pl-model-common': 1.46.4 - '@milaboratories/pl-model-middle-layer': 1.30.11 - '@milaboratories/ptabler-expression-js': 1.2.33 + '@milaboratories/pl-model-common': 1.47.1 + '@milaboratories/pl-model-middle-layer': 1.30.13 + '@milaboratories/ptabler-expression-js': 1.2.35 canonicalize: 2.1.0 es-toolkit: 1.47.0 fast-json-patch: 3.1.1 + lru-cache: 11.5.1 utility-types: 3.11.0 zod: 3.25.76 - '@platforma-sdk/package-builder-lib@1.1.0': + '@platforma-sdk/package-builder-lib@1.2.0': dependencies: '@aws-sdk/client-s3': 3.859.0 '@aws-sdk/lib-storage': 3.859.0(@aws-sdk/client-s3@3.859.0) @@ -6983,9 +7047,9 @@ snapshots: - bare-buffer - react-native-b4a - '@platforma-sdk/package-builder@3.14.0': + '@platforma-sdk/package-builder@3.14.1': dependencies: - '@platforma-sdk/package-builder-lib': 1.1.0 + '@platforma-sdk/package-builder-lib': 1.2.0 commander: 15.0.0 winston: 3.19.0 transitivePeerDependencies: @@ -6994,22 +7058,22 @@ snapshots: - bare-buffer - react-native-b4a - '@platforma-sdk/tengo-builder@4.0.15': + '@platforma-sdk/tengo-builder@4.0.18': dependencies: - '@milaboratories/pl-model-backend': 1.4.13 + '@milaboratories/pl-model-backend': 1.4.16 '@milaboratories/resolve-helper': 1.1.3 '@milaboratories/tengo-tester': 1.6.4 - '@milaboratories/ts-helpers': 1.8.4 + '@milaboratories/ts-helpers': 1.8.5 commander: 15.0.0 winston: 3.19.0 - '@platforma-sdk/test@1.79.28(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1)(vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(yaml@2.9.0))': + '@platforma-sdk/test@1.80.5(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1)(vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(yaml@2.9.0))': dependencies: - '@milaboratories/computable': 2.9.6 - '@milaboratories/pl-client': 3.13.2 - '@milaboratories/pl-middle-layer': 1.65.3(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1) - '@milaboratories/pl-tree': 1.12.18 - '@platforma-sdk/model': 1.79.27 + '@milaboratories/computable': 2.9.7 + '@milaboratories/pl-client': 3.14.2 + '@milaboratories/pl-middle-layer': 1.66.4(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1) + '@milaboratories/pl-tree': 1.13.1 + '@platforma-sdk/model': 1.80.2 '@vitest/coverage-istanbul': 4.1.8(vitest@4.0.18(@types/node@25.9.1)(lightningcss@1.32.0)(yaml@2.9.0)) vitest: 4.1.8(@types/node@25.9.1)(@vitest/coverage-istanbul@4.1.8)(vite@7.3.5(@types/node@25.9.1)(lightningcss@1.32.0)(yaml@2.9.0)) transitivePeerDependencies: @@ -7033,13 +7097,13 @@ snapshots: - supports-color - vite - '@platforma-sdk/test@1.79.28(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.27.7)(yaml@2.9.0))': + '@platforma-sdk/test@1.80.5(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.27.7)(yaml@2.9.0))': dependencies: - '@milaboratories/computable': 2.9.6 - '@milaboratories/pl-client': 3.13.2 - '@milaboratories/pl-middle-layer': 1.65.3(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1) - '@milaboratories/pl-tree': 1.12.18 - '@platforma-sdk/model': 1.79.27 + '@milaboratories/computable': 2.9.7 + '@milaboratories/pl-client': 3.14.2 + '@milaboratories/pl-middle-layer': 1.66.4(@bytecodealliance/preview2-shim@0.17.9)(@types/node@25.9.1) + '@milaboratories/pl-tree': 1.13.1 + '@platforma-sdk/model': 1.80.2 '@vitest/coverage-istanbul': 4.1.8(vitest@4.1.8) vitest: 4.1.8(@types/node@25.9.1)(@vitest/coverage-istanbul@4.1.8)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.27.7)(yaml@2.9.0)) transitivePeerDependencies: @@ -7063,12 +7127,13 @@ snapshots: - supports-color - vite - '@platforma-sdk/ui-vue@1.79.27(@bytecodealliance/preview2-shim@0.17.9)(@vue/compiler-dom@3.5.35)(@vue/server-renderer@3.5.35(vue@3.5.24(typescript@6.0.3)))(typescript@6.0.3)': + '@platforma-sdk/ui-vue@1.80.4(@bytecodealliance/preview2-shim@0.17.9)(@vue/compiler-dom@3.5.35)(@vue/server-renderer@3.5.35(vue@3.5.24(typescript@6.0.3)))(typescript@6.0.3)': dependencies: - '@milaboratories/pf-spec-driver': 1.4.18(@bytecodealliance/preview2-shim@0.17.9) - '@milaboratories/pl-model-common': 1.46.4 - '@milaboratories/uikit': 2.15.13(@vue/compiler-dom@3.5.35)(@vue/server-renderer@3.5.35(vue@3.5.24(typescript@6.0.3)))(typescript@6.0.3) - '@platforma-sdk/model': 1.79.27 + '@milaboratories/columns-collection-driver': 0.2.1 + '@milaboratories/pf-spec-driver': 1.4.21(@bytecodealliance/preview2-shim@0.17.9) + '@milaboratories/pl-model-common': 1.47.1 + '@milaboratories/uikit': 2.15.16(@vue/compiler-dom@3.5.35)(@vue/server-renderer@3.5.35(vue@3.5.24(typescript@6.0.3)))(typescript@6.0.3) + '@platforma-sdk/model': 1.80.2 '@types/d3-format': 3.0.4 '@types/node': 24.5.2 '@types/semver': 7.7.1 @@ -7101,12 +7166,12 @@ snapshots: - typescript - universal-cookie - '@platforma-sdk/workflow-tengo@6.6.5': + '@platforma-sdk/workflow-tengo@6.7.2': dependencies: - '@milaboratories/pframes-rs-wasip2': 1.1.52 + '@milaboratories/pframes-rs-wasip2': 1.1.55 '@milaboratories/software-pframes-conv': 2.2.9 - '@platforma-open/milaboratories.software-ptabler': 2.1.3 - '@platforma-open/milaboratories.software-ptexter': 1.2.2 + '@platforma-open/milaboratories.software-ptabler': 2.1.6 + '@platforma-open/milaboratories.software-ptexter': 1.2.3 '@platforma-open/milaboratories.software-small-binaries': 2.1.1 '@protobuf-ts/grpc-transport@2.11.1(@grpc/grpc-js@1.13.5)': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 6af935c..83d87d9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -10,13 +10,13 @@ catalog: "@milaboratories/ts-builder": 1.6.0 "@milaboratories/ts-configs": 1.3.0 "typescript": ~5.9.3 - "@platforma-sdk/workflow-tengo": 6.6.5 - "@platforma-sdk/block-tools": 2.11.10 - "@platforma-sdk/model": 1.79.27 - "@platforma-sdk/ui-vue": 1.79.27 - "@platforma-sdk/test": 1.79.28 - "@platforma-sdk/tengo-builder": 4.0.15 - "@platforma-sdk/package-builder": 3.14.0 + "@platforma-sdk/workflow-tengo": 6.7.2 + "@platforma-sdk/block-tools": 2.12.7 + "@platforma-sdk/model": 1.80.2 + "@platforma-sdk/ui-vue": 1.80.4 + "@platforma-sdk/test": 1.80.5 + "@platforma-sdk/tengo-builder": 4.0.18 + "@platforma-sdk/package-builder": 3.14.1 "@platforma-sdk/blocks-deps-updater": 2.2.0 "vue": 3.5.24 diff --git a/software/src_python/main.py b/software/src_python/main.py index 420d358..688ccfe 100644 --- a/software/src_python/main.py +++ b/software/src_python/main.py @@ -64,6 +64,7 @@ import json import multiprocessing as mp import os +import re import sys import time from dataclasses import dataclass @@ -87,6 +88,17 @@ # chains into small ones. DEFAULT_TOKEN_BUDGET = 16384 +# GPU token-budget auto-sizing (see resolve_gpu_token_budget). On CUDA the token +# budget is what bounds VRAM per forward pass, so we scale it from the VRAM the +# workflow allocated (PLATFORMA_GPU_MEMORY) — mirroring how --max-memory-gb sizes +# the host-RAM path. Tokens-per-GB is deliberately conservative (~2× headroom vs +# the measured hidden-state cost of the widest wired model); the halve-on-OOM +# retry in Embedder._forward is the backstop if a forward still overshoots. +GPU_TOKENS_PER_GB = 4096 +GPU_RESERVE_GB = 1.0 # fragmentation + attention/temporary buffers headroom +MIN_TOKEN_BUDGET = 4096 # floor: keep batches large enough to amortise kernel launches +MAX_TOKEN_BUDGET = 131072 # ceiling: past this, padding waste and scheduling dominate + # Single process by default; the GPU tier always runs single-process regardless. # Opt into CPU fan-out with --workers N (or 0 to auto-size from the CPU budget). DEFAULT_WORKERS = 1 @@ -207,6 +219,57 @@ def estimate_model_gb(model_path: str) -> float: return gb if gb > 0 else 1.0 # fall back to ~1 GB if nothing is found +def parse_gpu_memory_env() -> float: + """VRAM the workflow allocated to this exec, in GB, from PLATFORMA_GPU_MEMORY. + + The backend emits that env in one of two shapes: a plain byte count (local + exec) or a k8s/SI quantity like ``16Gi`` / ``8G`` (the Kueue job template). + Returns 0.0 when the env is unset or unparseable — the caller then falls back + to the static token-budget default.""" + raw = os.environ.get("PLATFORMA_GPU_MEMORY", "").strip() + if not raw: + return 0.0 + if raw.isdigit(): # local exec: raw bytes + return int(raw) / 1e9 + m = re.fullmatch(r"(\d+(?:\.\d+)?)\s*([KMGTP]i?)?B?", raw) # k8s / SI quantity + if not m: + log_message(f"could not parse PLATFORMA_GPU_MEMORY={raw!r}; using default token budget", + "WARNING") + return 0.0 + value = float(m.group(1)) + suffix = m.group(2) or "" + binary = {"Ki": 2 ** 10, "Mi": 2 ** 20, "Gi": 2 ** 30, "Ti": 2 ** 40, "Pi": 2 ** 50} + decimal = {"K": 1e3, "M": 1e6, "G": 1e9, "T": 1e12, "P": 1e15} + mult = binary.get(suffix, decimal.get(suffix, 1.0)) + return value * mult / 1e9 + + +def resolve_gpu_token_budget(args, device, model_path: str, model_family: str) -> int: + """Tokens per forward pass, sized from the allocated VRAM on the GPU path. + + On CUDA the token budget is the lever that bounds VRAM, so we size it from the + VRAM the workflow requested (PLATFORMA_GPU_MEMORY): a larger request → larger + batches → higher throughput; a smaller request stays safe. This is the GPU + analogue of ``--max-memory-gb`` for host RAM. An explicit --token-budget wins; + off the CUDA path, or with no VRAM signal, we keep the static default. The + halve-on-OOM retry in Embedder._forward remains the backstop if a forward + still overshoots the estimate.""" + if args.token_budget is not None and args.token_budget > 0: + return args.token_budget # explicit operator override always wins + if device.type != "cuda": # budget only bounds VRAM; CPU/MPS keep the default + return DEFAULT_TOKEN_BUDGET + gpu_gb = parse_gpu_memory_env() + if gpu_gb <= 0: + return DEFAULT_TOKEN_BUDGET + # Standard HF encoders load fp16 on CUDA; custom (trust_remote_code) models stay + # fp32 — mirror Embedder.dtype so the weights term matches the resident copy. + fp16 = model_family != "hf-custom" + weights_gb = estimate_model_gb(model_path) * (0.5 if fp16 else 1.0) + avail_gb = max(0.5, gpu_gb - weights_gb - GPU_RESERVE_GB) + budget = int(avail_gb * GPU_TOKENS_PER_GB) + return max(MIN_TOKEN_BUDGET, min(budget, MAX_TOKEN_BUDGET)) + + def resolve_parallelism(args, device, model_path: str) -> "tuple[int, int]": """Decide (workers, threads_per_worker) for the run. @@ -1207,8 +1270,10 @@ def main() -> int: "all non-pad tokens.") parser.add_argument("--max-length", type=int, default=DEFAULT_MAX_LENGTH, help="Max residue tokens incl. specials; longer sequences truncate from the C-terminus") - parser.add_argument("--token-budget", type=int, default=DEFAULT_TOKEN_BUDGET, - help="Max tokens (batch × padded length) per forward pass") + parser.add_argument("--token-budget", type=int, default=None, + help="Max tokens (batch × padded length) per forward pass. On CUDA, " + "auto-sized from allocated VRAM (PLATFORMA_GPU_MEMORY) unless set here. " + f"Unset elsewhere defaults to {DEFAULT_TOKEN_BUDGET}.") parser.add_argument("--workers", type=int, default=DEFAULT_WORKERS, help="CPU inference processes. 1 = single process (default); " "0 = auto (size from --cpus: ~2 threads/worker, total ≈ cpus, " @@ -1247,6 +1312,12 @@ def main() -> int: device = resolve_device(plan.device) + # Tokens per forward pass. On CUDA this is sized from the allocated VRAM + # (PLATFORMA_GPU_MEMORY) so the workflow's VRAM request drives the GPU batch + # size; elsewhere it is the static default. Computed once and shared by every + # embedder below (they all take it as `token_budget`). + token_budget = resolve_gpu_token_budget(args, device, args.model_path, args.model_family) + # Decide CPU parallelism (workers × intra-op threads). Auto sizing and the # GPU/MPS single-process guard live in resolve_parallelism. workers, threads_per_worker = resolve_parallelism(args, device, args.model_path) @@ -1254,27 +1325,27 @@ def main() -> int: trust_remote_code = args.model_family == "hf-custom" if args.model_family == "ablang2": # The pip model runs single-process regardless of --workers (see class doc). - embedder = AbLang2Embedder(args.model_path, device, args.max_length, args.token_budget, + embedder = AbLang2Embedder(args.model_path, device, args.max_length, token_budget, input_kind=args.input_kind) workers, threads_per_worker = 1, 0 parallel_note = "ablang2 (single process)" elif trust_remote_code: # Custom trust_remote_code model (PeptideCLM-2): single process — spawn + the # dynamic module import is fragile. Load once in-process; let torch use all cores. - embedder = Embedder(args.model_path, device, args.max_length, args.token_budget, + embedder = Embedder(args.model_path, device, args.max_length, token_budget, threads=0, input_kind=args.input_kind, trust_remote_code=True, emb_layer=args.emb_layer, pool_special_tokens=args.pool_special_tokens) workers, threads_per_worker = 1, 0 parallel_note = "hf-custom (single process)" elif workers > 1: - embedder = ParallelEmbedder(args.model_path, device, args.max_length, args.token_budget, + embedder = ParallelEmbedder(args.model_path, device, args.max_length, token_budget, workers, threads_per_worker, input_kind=args.input_kind, trust_remote_code=trust_remote_code, emb_layer=args.emb_layer, pool_special_tokens=args.pool_special_tokens) parallel_note = f"workers={workers}×{threads_per_worker} threads/worker" else: - embedder = Embedder(args.model_path, device, args.max_length, args.token_budget, + embedder = Embedder(args.model_path, device, args.max_length, token_budget, threads=threads_per_worker, input_kind=args.input_kind, trust_remote_code=trust_remote_code, emb_layer=args.emb_layer, pool_special_tokens=args.pool_special_tokens) @@ -1284,7 +1355,8 @@ def main() -> int: # Record device + checkpoint at startup so the operator sees what ran. log_message(f"device={device.type} dtype={embedder.dtype} model={model_name} dim={embedder.dim} " - f"{parallel_note} (requested={plan.device}, scopes={len(plan.scopes)})", + f"token_budget={token_budget} {parallel_note} " + f"(requested={plan.device}, scopes={len(plan.scopes)})", "STEP") stats: dict = { diff --git a/ui/src/pages/MainPage.vue b/ui/src/pages/MainPage.vue index 3110c99..cb23df9 100644 --- a/ui/src/pages/MainPage.vue +++ b/ui/src/pages/MainPage.vue @@ -122,7 +122,10 @@ const slowOnCpu = computed(() => { :step="1" :maxValue="1012" > - + { :step="1" :maxValue="128" > - + diff --git a/workflow/src/compute-embeddings.tpl.tengo b/workflow/src/compute-embeddings.tpl.tengo index 641f23b..2f25ac9 100644 --- a/workflow/src/compute-embeddings.tpl.tengo +++ b/workflow/src/compute-embeddings.tpl.tengo @@ -34,8 +34,12 @@ self.body(func(inputs) { modelTag := inputs.modelTag // checkpoint id + --model-name identity keyCol := inputs.keyCol // entity-key column header in the batch TSV device := inputs.device // "cpu" | "gpu" (gates the GPU request) - cpu := is_undefined(inputs.cpu) ? 16 : inputs.cpu - memGiB := is_undefined(inputs.mem) ? 32 : inputs.mem + + // Advanced-settings resource overrides (either may be unset). When present, the + // static value wins over the data-driven formula for that dimension, on both the + // CPU and GPU paths (below). mem is given in GiB. + cpuOverride := inputs.cpu // number | undefined + ramOverride := is_undefined(inputs.mem) ? undefined : string(inputs.mem) + "GiB" // Per-model recipe (inputKind, loader family, pairMode, embLayer, poolSpecials) // comes from the central registry (models.lib) — the single source of truth, @@ -71,10 +75,8 @@ self.body(func(inputs) { builder := exec.builder(). software(soft). - mem(string(memGiB) + "GiB"). - cpu(cpu). addAsset(modelAsset, "model"). - addFile("batch.tsv", batchFile). + addFile("batch.tsv", batchFile, { tag: "batch" }). writeFile("plan.json", planJson). arg("--input").arg("batch.tsv"). arg("--plan").arg("plan.json"). @@ -97,13 +99,45 @@ self.body(func(inputs) { // @TODO: Update SDK and get mkDir("embeddings") once the fix that // prevents it to create "[\"embeddings\"]" folder is released. - // GPU vs CPU tier is decided by the plan's device. + // GPU vs CPU tier is decided by the plan's device (itself set from exec.hasGpu in + // main.tpl). Each path declares its resources via `.resources()`; an advanced- + // settings override (cpuOverride / ramOverride) wins per dimension where set. + f := exec.formula if device == "gpu" { - builder.gpuMemory("16GiB") + // GPU: the accelerator does the work in ONE streaming process, so the host only + // tokenizes and writes Parquet interleaved with the forward pass — no separable + // CPU-heavy phase (the heavy PColumn->batch-TSV shaping is upstream CPU execs). + // So keep the host footprint MINIMAL and sized to fit the cheapest fractional-L4 + // node: cpu 2 + ram 8 GiB fit a g6f.xlarge (4 vCPU / 16 GiB), and the model-tiered + // vram (3 GiB small / 6 GiB large, models.gpuVramGiB) selects gpu-3g / gpu-6g — + // never the 4×L40S g6e.12xlarge the old 16/32/16 request forced. vram rides to the + // runner as PLATFORMA_GPU_MEMORY (sizes the token budget); host RAM via the + // --max-memory-gb {system.ram.gb} arg above. No --workers/--cpus (single process). + builder.resources({ + onGPU: { + cpu: is_undefined(cpuOverride) ? 2 : cpuOverride, + ram: is_undefined(ramOverride) ? "8GiB" : ramOverride, + vram: string(models.gpuVramGiB(modelTag)) + "GiB" + } + }) } else { builder. arg("--workers").arg("0"). arg("--cpus").argExpr("{system.cpu}") + + // CPU: throughput scales with cores (workers × intra-op threads), and the + // per-batch work ~= its token volume ~= the batch TSV byte size. Size cores + // from it (4..16) and RAM to 2 GiB/core (8..32 GiB) so ~cores/2 resident model + // copies fit — the fan-out the runner auto-sizes from --max-memory-gb. Both + // dimensions carry a .staticFallback equal to the old fixed 16 / 32 GiB, used + // on backends that cannot evaluate resource formulas. + cores := f.size("batch").dividedBy(f.mib(2)).between(4, 16) + builder.resources({ + onCPU: { + cpu: is_undefined(cpuOverride) ? cores.staticFallback(16) : cpuOverride, + ram: is_undefined(ramOverride) ? cores.times(f.gib(2)).staticFallback("32GiB") : ramOverride + } + }) } run := builder. diff --git a/workflow/src/compute-stats.tpl.tengo b/workflow/src/compute-stats.tpl.tengo index d0434f0..e1b1438 100644 --- a/workflow/src/compute-stats.tpl.tengo +++ b/workflow/src/compute-stats.tpl.tengo @@ -81,11 +81,26 @@ self.body(func(inputs) { // Canonical encoding keeps the plan bytes deterministic. planJson := string(canonical.encode({ device: inputs.device, scopes: planScopes })) + // The counting pass loads the whole source TSV into memory (read_csv, all columns + // Utf8), so its RAM tracks the source size rather than a flat budget: ~3× the TSV + // bytes (DataFrame + transient copies + arrow) on a 2 GiB base, floored at the old + // 4 GiB for small inputs and capped at 32 GiB. cpu gets a couple of cores on large + // files for the parse. Both fall back to the old fixed 4 GiB / 1 core on backends + // that cannot evaluate resource formulas. (The seqTb builder above stays light — + // ptabler streams with disk spill, so the metaInput 1 core / 4 GiB is enough.) + f := exec.formula run := exec.builder(). software(soft). - cpu(cpu). - mem(string(memGiB) + "GiB"). - addFile("source.tsv", sourceTsv). + // Register the tagged input before the formula that references it (tag lookup + // is resolved at build time, so order is not functionally required — but this + // mirrors compute-embeddings and removes any ambiguity). + addFile("source.tsv", sourceTsv, { tag: "source" }). + resources({ + onCPU: { + cpu: f.size("source").dividedBy(f.gib(1)).between(1, 4).staticFallback(1), + ram: f.size("source").times(3).plus(f.gib(2)).between(f.gib(4), f.gib(32)).staticFallback("4GiB") + } + }). writeFile("plan.json", planJson). arg("--stats-only"). arg("--input").arg("source.tsv"). diff --git a/workflow/src/main.tpl.tengo b/workflow/src/main.tpl.tengo index b01306a..84a01a4 100644 --- a/workflow/src/main.tpl.tengo +++ b/workflow/src/main.tpl.tengo @@ -109,9 +109,17 @@ wf.body(func(args) { minBatch = MIN_BATCH_GPU } - // Advanced resource overrides for the embedding execs. - embedCpu := is_undefined(args.cpu) ? 16 : args.cpu - embedMemGiB := is_undefined(args.mem) ? 32 : args.mem + // Advanced resource overrides for the embedding execs. Passed through RAW + // (possibly unset) as metaExtra below: compute-embeddings uses a static override + // where present and its data-driven resource formula where absent. metaExtra is + // scheduling-only (CID-transparent), so conditionally including a key is dedup-safe. + embedMeta := {} + if !is_undefined(args.cpu) { + embedMeta.cpu = smart.createJsonResource(args.cpu) + } + if !is_undefined(args.mem) { + embedMeta.mem = smart.createJsonResource(args.mem) + } // Provenance trace seeded from the input dataset. The trace label and id carry // the MODEL, so two columns embedding the same scope with different models get @@ -226,10 +234,7 @@ wf.body(func(args) { keyCol: smart.createJsonResource(keyAxisName), device: smart.createJsonResource(device) }, - metaExtra: { - cpu: smart.createJsonResource(embedCpu), - mem: smart.createJsonResource(embedMemGiB) - } + metaExtra: embedMeta } ) diff --git a/workflow/src/models.lib.tengo b/workflow/src/models.lib.tengo index ad170cd..bda1964 100644 --- a/workflow/src/models.lib.tengo +++ b/workflow/src/models.lib.tengo @@ -88,6 +88,29 @@ label := func(tag) { return m.label } +// GPU VRAM to request for a tag, in GiB. This is a SCHEDULING request — it selects +// the GPU node tier (backend maps it to the `platforma.bio/gpu-memory-gib` node +// selector) and rides to the runner as PLATFORMA_GPU_MEMORY, which sizes the GPU +// token budget (see software main.py resolve_gpu_token_budget). It is NOT a hard +// cap: the forward pass is token-budgeted with a halve-on-OOM retry. +// +// Kept as small as safely fits so the job lands on the CHEAP fractional-L4 g6f +// tiers, never the big 4×L40S g6e.12xlarge (gpu-96g). Two tiers by model width: +// - dim <= 768 (BERT-base-scale: H3BERTa/VHHBERT/TCR-BERT, AbLang2, ESM-2 150M) +// -> 3 GiB -> gpu-3g (g6f.xlarge). Footprint ~1.5 GiB (CUDA context + <=0.3 GiB +// fp16 weights + a few 100 MB activations), so 3 GiB has margin even at the +// default token budget. +// - dim >= 1024 (ESM-2 650M, CurrAb, fp32 PeptideCLM-2) -> 6 GiB -> gpu-6g +// (g6f.2xlarge). Peak ~3.7 GiB for ESM-2 650M at the default budget; 6 GiB +// leaves headroom and the adaptive budget shrinks batches when VRAM is tighter. +gpuVramGiB := func(tag) { + m := MODELS[tag] + if is_undefined(m) { + return 6 // unknown tag: the safer of the two small tiers + } + return m.dim >= 1024 ? 6 : 3 +} + // Final output vector length for a (scope, model): the base width D, doubled for a // paired Fv scope embedded by a non-joint (concat) model — VH⊕VL → 2D. Single // chains, scFv, and joint-Fv (CurrAb/AbLang2) stay at D. undefined for an unmapped @@ -108,5 +131,6 @@ export ll.toStrict({ resolveModelTag: resolveModelTag, get: get, label: label, + gpuVramGiB: gpuVramGiB, outputVectorLength: outputVectorLength })