@7n/llm-lib 2.10.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.11.0] - 2026-07-27
4
+
5
+ ### Added
6
+
7
+ - `submitBatch` тепер обирає між клієнтською емуляцією і справжнім `/v1/batches` litellm batch-adapter-а (`backend: 'auto'|'emulated'|'openai-batches'`) — автоматично вмикається, коли резолвлений провайдер `litellm` і адаптер відповідає на capability-пробу.
8
+
9
+ ## [2.10.1] - 2026-07-27
10
+
11
+ ### Fixed
12
+
13
+ - Smoke-тест `resolveModel` через живий napi-аддон стабільний під `bun run --bun vitest`: каскад ганяється в дочірньому процесі з env при spawn, бо Bun не передає записи `process.env` у нативний environ (Rust `env::var` бачив ambient-значення замість `vi.stubEnv`)
14
+
3
15
  ## [2.10.0] - 2026-07-27
4
16
 
5
17
  ### Added
package/lib/batch.mjs CHANGED
@@ -1,14 +1,18 @@
1
1
  /**
2
- * Тип 2b (OpenAI-сумісний API, batch) — **лише емуляція** у v1 (рішення Р,
3
- * задача T6): чанкований конкурентний прогін через Тип 2a
4
- * (`llm_lib::local_cloud`) під інтерфейсом `submit progress → results` —
5
- * той самий інтерфейс, яким говорив би й справжній OpenAI Batch API
6
- * (`/v1/batches`, v2), якому локальний omlx (перший споживач) не має.
2
+ * Тип 2b (OpenAI-сумісний API, batch) — `submitBatch` обирає між клієнтською
3
+ * емуляцією (v1, чанкований конкурентний прогін через Тип 2a
4
+ * `llm_lib::local_cloud`) і справжнім `/v1/batches` litellm batch-adapter-а
5
+ * (спека `docs/specs/2026-07-27-batch-local-avg-real-batches.md`), під тим
6
+ * самим інтерфейсом `submit progress results` для обох. Вибір —
7
+ * `backend` (дефолт `'auto'`: реальний Batch API лише коли резолвлений
8
+ * провайдер `litellm` і кешована мережева проба адаптера пройшла; локальний
9
+ * omlx завжди йде емуляцією).
7
10
  *
8
- * Тонкий JS-клієнт до Rust-крейта `llm_lib::batch` через napi FFI
9
- * in-process (`llm-lib/crates/llm-lib-napi`) — жодного власного чанкінгу
10
- * тут (анти-приклад, якого це узагальнює: `mlmail/use-summary.js` чанкує
11
- * переклади проти omlx вручну, з вистражданими лімітами).
11
+ * Тонкий JS-клієнт до Rust-крейта `llm_lib::batch`/`llm_lib::remote_batch`
12
+ * через napi FFI in-process (`llm-lib/crates/llm-lib-napi`) — жодного
13
+ * власного чанкінгу чи HTTP тут (анти-приклад, якого це узагальнює:
14
+ * `mlmail/use-summary.js` чанкує переклади проти omlx вручну, з
15
+ * вистражданими лімітами).
12
16
  */
13
17
  import { loadNative } from './internal/native.mjs'
14
18
 
@@ -23,9 +27,9 @@ import { loadNative } from './internal/native.mjs'
23
27
  */
24
28
 
25
29
  /**
26
- * Емуляція batch-виклику Типу 2b. `modelSpecOrTier` — той самий контракт,
27
- * що й у [`oneShotLocalCloud`] з `local-cloud.mjs`: явний
28
- * `"provider/model-id"` або абстрактний тир (`min`/`avg`/`max`).
30
+ * Batch-виклик Типу 2b. `modelSpecOrTier` — той самий контракт, що й у
31
+ * [`oneShotLocalCloud`] з `local-cloud.mjs`: явний `"provider/model-id"`
32
+ * або абстрактний тир (`min`/`avg`/`max`).
29
33
  * @param {string} modelSpecOrTier `"provider/model-id"` або `'min'|'avg'|'max'`
30
34
  * @param {BatchItem[]} items вхідні items (`customId` — унікальний у межах виклику)
31
35
  * @param {{
@@ -33,6 +37,9 @@ import { loadNative } from './internal/native.mjs'
33
37
  * system?: string,
34
38
  * chunkSize?: number,
35
39
  * concurrency?: number,
40
+ * backend?: 'emulated' | 'openai-batches' | 'auto',
41
+ * pollIntervalMs?: number,
42
+ * pollTimeoutMs?: number,
36
43
  * onProgress?: (completed: number, total: number) => void,
37
44
  * native?: {
38
45
  * submitBatch: (
@@ -43,13 +50,13 @@ import { loadNative } from './internal/native.mjs'
43
50
  * onProgress?: (completed: number, total: number) => void
44
51
  * ) => Promise<BatchResult[]>
45
52
  * }
46
- * }} [options] конфіг локальних провайдерів, ліміти чанка/конкурентності, progress-колбек, інжект `native` для тестів
53
+ * }} [options] конфіг локальних провайдерів, ліміти чанка/конкурентності/бекенда/опитування, progress-колбек, інжект `native` для тестів
47
54
  * @returns {Promise<BatchResult[]>} результати в тому самому порядку, що й вхідні `items`
48
55
  */
49
56
  export function submitBatch(
50
57
  modelSpecOrTier,
51
58
  items,
52
- { localProviders, system, chunkSize, concurrency, onProgress, native } = {}
59
+ { localProviders, system, chunkSize, concurrency, backend, pollIntervalMs, pollTimeoutMs, onProgress, native } = {}
53
60
  ) {
54
61
  const nativeImpl = native ?? loadNative()
55
62
  return nativeImpl.submitBatch(
@@ -65,7 +72,10 @@ export function submitBatch(
65
72
  },
66
73
  {
67
74
  chunkSize: chunkSize ?? undefined,
68
- concurrency: concurrency ?? undefined
75
+ concurrency: concurrency ?? undefined,
76
+ backend: backend ?? undefined,
77
+ pollIntervalMs: pollIntervalMs ?? undefined,
78
+ pollTimeoutMs: pollTimeoutMs ?? undefined
69
79
  },
70
80
  onProgress ?? undefined
71
81
  )
package/lib/docs/batch.md CHANGED
@@ -3,7 +3,7 @@ type: JS Module
3
3
  title: batch.mjs
4
4
  resource: llm-lib/lib/batch.mjs
5
5
  docgen:
6
- crc: 4412e8c2
6
+ crc: 5e13af10
7
7
  model: openai-codex/gpt-5.4-mini
8
8
  tier: cloud-min
9
9
  score: 100
@@ -12,22 +12,40 @@ docgen:
12
12
 
13
13
  ## Огляд
14
14
 
15
- Тонкий JS-клієнт до `llm_lib::batch` у `llm-lib/crates/llm-lib-napi`, який через in-process `napi FFI` лише емулює Type 2b у v1: під одним `submit → progress → results` інтерфейсом він прокидає batch-запит у `llm_lib::local_cloud` і повертає результат як сумісний OpenAI Batch API-контракт для майбутнього `/v1/batches`. Єдина публічна точка входу — `submitBatch`. Це узагальнення анти-прикладу на кшталт `mlmail/use-summary.js`, де чанкінг доводиться робити вручну під обмеження провайдера.
15
+ Тип 2b (OpenAI-сумісний API, batch) — `submitBatch` обирає між клієнтською
16
+ емуляцією (v1, чанкований конкурентний прогін через Тип 2a
17
+ `llm_lib::local_cloud`) і справжнім `/v1/batches` litellm batch-adapter-а
18
+ (спека `docs/specs/2026-07-27-batch-local-avg-real-batches.md`), під тим
19
+ самим інтерфейсом `submit → progress → results` для обох. Вибір —
20
+ `backend` (дефолт `'auto'`: реальний Batch API лише коли резолвлений
21
+ провайдер `litellm` і кешована мережева проба адаптера пройшла; локальний
22
+ omlx завжди йде емуляцією).
23
+
24
+ Тонкий JS-клієнт до Rust-крейта `llm_lib::batch`/`llm_lib::remote_batch`
25
+ через napi FFI in-process (`llm-lib/crates/llm-lib-napi`) — жодного
26
+ власного чанкінгу чи HTTP тут (анти-приклад, якого це узагальнює:
27
+ `mlmail/use-summary.js` чанкує переклади проти omlx вручну, з
28
+ вистражданими лімітами).
16
29
 
17
30
  ## Поведінка
18
31
 
19
- 1. `submitBatch` приймає batch-запит для Type 2b і передає його в native-реалізацію, щоб отримати той самий бізнес-інтерфейс `submit → progress → results`, який очікується від batch-потоку поверх локальних провайдерів.
20
- 2. `submitBatch` зберігає порядок вхідних items у результатах, щоб кожен результат можна було зіставити з початковим `customId`.
21
- 3. `submitBatch` нормалізує вхідні items перед передачею далі: бере `customId` і `prompt` як є, а відсутній `system` не підміняє значенням.
22
- 4. `submitBatch` передає конфіг локальних провайдерів, загальний `system`, а також ліміти chunking і concurrency у native-шар, щоб контроль виконання залишався в реалізації batch-крейта.
23
- 5. `submitBatch` підтримує `onProgress`, щоб викликати повідомлення про хід виконання під час обробки batch-у.
24
- 6. `submitBatch` дозволяє підмінити native-реалізацію для тестів, не змінюючи зовнішню поведінку публічного API.
32
+ submitBatch повертає результати в тому ж порядку, що й вхідні items; для кожного item результат містить або `ok`, або `error`.
33
+
34
+ Для кожного item `customId` має бути унікальним у межах одного виклику; конфлікт ідентифікаторів лишається на стороні викликача.
35
+
36
+ За помилок виконання batch у відповіді зберігається один результат на кожен вхідний item, тож користувацький контракт не зводиться до часткової втрати елементів.
37
+
38
+ `onProgress`, якщо заданий, отримує агрегований прогрес виконання для всього набору items.
25
39
 
26
40
  ## Публічний API
27
41
 
28
- - submitBatch — Емуляція batch-виклику Типу 2b. `modelSpecOrTier` — той самий контракт,
29
- що й у [`oneShotLocalCloud`] з `local-cloud.mjs`: явний
30
- `"provider/model-id"` або абстрактний тир (`min`/`avg`/`max`).
42
+ - submitBatch — Batch-виклик Типу 2b. `modelSpecOrTier` — той самий контракт, що й у
43
+ [`oneShotLocalCloud`] з `local-cloud.mjs`: явний `"provider/model-id"`
44
+ або абстрактний тир (`min`/`avg`/`max`).
45
+
46
+ ## Сценарії використання
47
+
48
+ - `llm-lib/tests/batch.test.mjs` (submitBatch) — делегує modelSpecOrTier/items у native.submitBatch і віддає його результат; явний; кожен item нормалізується до {customId, prompt, system}, навіть без власного system; localProviders/system/chunkSize/concurrency прокидаються в options/config; onProgress прокидається останнім аргументом; ще 2
31
49
 
32
50
  ## Гарантії поведінки
33
51
 
@@ -3,31 +3,27 @@ type: JS Module
3
3
  title: model-tiers.mjs
4
4
  resource: llm-lib/lib/model-tiers.mjs
5
5
  docgen:
6
- crc: 16df44f1
6
+ crc: 05c5eb6a
7
7
  model: openai-codex/gpt-5.4-mini
8
8
  tier: cloud-min
9
9
  score: 100
10
- issues: judge-refine:kept-original,judge:inaccurate:0.98
10
+ issues: judge-refine:kept-original,judge:inaccurate:0.97
11
11
  judgeModel: openai-codex/gpt-5.4-mini
12
12
  ---
13
13
 
14
14
  ## Огляд
15
15
 
16
- Публічний шар модуля зосереджений на виборі та нормалізації моделей: `resolveModel`, `parseModelId`, `formatModelSpec`, `isLocalModel`, `thinkingLevelForTier` і константах `LOCAL_MIN`, `LOCAL_AVG`, `LOCAL_MAX`, `CLOUD_MIN`, `CLOUD_AVG`, `CLOUD_MAX`.
17
-
18
- Він узгоджує представлення моделі між tier і форматом `"provider/model-id"`, дає змогу відрізняти локальні моделі від хмарних і окремо пов’язує tier із рівнем thinking.
16
+ `LOCAL_MIN`, `LOCAL_AVG`, `LOCAL_MAX`, `CLOUD_MIN`, `CLOUD_AVG` і `CLOUD_MAX` задають спільні варіанти модельного рівня для локального та хмарного сценаріїв, щоб споживачі використовували однакові значення для вибору режиму роботи. `parseModelId` і `formatModelSpec` узгоджують подання модельного ідентифікатора між внутрішнім представленням і зовнішнім форматом, а `resolveModel` повертає уже погоджений варіант для подальшого використання. `thinkingLevelForTier` фіксує відповідність між tier і рівнем thinking, а `isLocalModel` дає змогу відрізнити локальні моделі від інших без дублювання цієї перевірки в різних місцях.
19
17
 
20
18
  ## Поведінка
21
19
 
22
- LOCAL_MIN, LOCAL_AVG, LOCAL_MAX, CLOUD_MIN, CLOUD_AVG і CLOUD_MAX це джерело політики вибору моделі: значення беруться з env і далі використовуються як канонічні тири для розв’язання model-spec та класифікації локальної чи хмарної моделі. Якщо відповідний env не заданий, значення лишається порожнім рядком, тож наступні кроки можуть повернути порожній результат замість конкретної моделі.
23
-
24
- resolveModel — центральна точка для отримання фактичного `"provider/model-id"` за абстрактним тиром. Вона спирається на канон тиру з native-шару, а невідомий тир відсікає одразу тут, щоб зберегти TypeError на рівні цього модуля. Результат або повертає готовий model-spec, або порожній рядок, якщо дефолт не визначений.
20
+ LOCAL_MIN, LOCAL_AVG, LOCAL_MAX, CLOUD_MIN, CLOUD_AVG і CLOUD_MAX беруть значення з environment на старті модуля та задають єдину політику вибору моделі для локального й хмарного шарів. Ці значення далі слугують опорою для resolveModel, який повертає вже фактично обраний model spec у форматі provider/model-id або порожній рядок, якщо дефолт провайдера лишився substrate-рівню. Невідомий tier відсіюється на цьому рівні як помилка контракту.
25
21
 
26
- parseModelId і formatModelSpec утворюють парну нормалізацію між рядковим spec та об’єктом моделі: перша розкладає зовнішній `"provider/model-id"` на складники, друга збирає фактично резолвлену модель назад у той самий формат. Це дозволяє пропускати через модуль як сирі spec-рядки, так і вже вибрані pi-моделі без втрати форми.
22
+ thinkingLevelForTier переводить rung-tier у дискретний рівень thinking, щоб downstream-логіка могла узгоджено трактувати силу моделі без повторного аналізу spec. local-min і local-min-retry зводяться до найнижчого рівня, cloud-min, cloud-avg і cloud-max піднімають рівень відповідно до потужності хмарного вибору.
27
23
 
28
- isLocalModel використовує спільні тири LOCAL_MIN, LOCAL_AVG і LOCAL_MAX як найвищий пріоритет, а для решти spec опирається на провайдера з `N_LLM_LOCAL_PROVIDERS`. Так модуль узгоджує явні локальні політики з ознакою провайдера й дає один бінарний сигнал для ланцюжків, що відрізняють local від cloud.
24
+ parseModelId і formatModelSpec утворюють парний обмін між рядковим model spec та об’єктом моделі: перший розбирає канонічний рядок на provider та id, другий збирає фактично резолвлену модель назад у той самий формат. Якщо spec або модель неповні, результатом є null, щоб не маскувати malformed або відсутній стан.
29
25
 
30
- thinkingLevelForTier не бере участі у резолву моделі, але працює поруч із тирами як окрема проєкція: перетворює rung-рівні на дискретний thinkingLevel для downstream-логіки. Це тримає вибір моделі та рівень міркування синхронними, але розділеними по відповідальності.
26
+ isLocalModel використовує ту саму політику, що й resolveModel: спочатку звіряє явні локальні тири, а потім визначає локальність за provider із model spec. Це дає спільне правило для агрегатів local/cloud і для рішень, де потрібно відрізнити локальний шлях від хмарного без дублювання логіки в consumers.
31
27
 
32
28
  ## Публічний API
33
29
 
@@ -62,6 +58,10 @@ pi-моделі (`session.model`), коли consumer лишив `modelSpec` по
62
58
  model-spec, не за наявністю запису в мапі. Використовується
63
59
  для local/cloud-агрегатів ланцюжків і рішення про chain-заголовки.
64
60
 
61
+ ## Сценарії використання
62
+
63
+ - `llm-lib/tests/model-tiers.test.mjs` (isLocalModel; parseModelId) — omlx-провайдер — локальний (дефолт N_LLM_LOCAL_PROVIDERS); litellm-провайдер — теж локальний за дефолтом (перемикач omlx/litellm через тир-env); порожній/malformed spec — не локальний; кастомний список провайдерів через env (ізольований re-import); звичайна пара; ще 8
64
+
65
65
  ## Гарантії поведінки
66
66
 
67
67
  - Власних операцій запису (ФС/БД) у файлі немає; виклики імпортованих модулів можуть писати.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@7n/llm-lib",
3
- "version": "2.10.0",
3
+ "version": "2.11.0",
4
4
  "description": "Тонкий шар роботи з LLM (локальні omlx + хмарні провайдери) поверх pi: model tiers, one-shot, agentic-раннери, write-guard, trace, telemetry, prompt-budget",
5
5
  "keywords": [
6
6
  "nitra",
@@ -56,8 +56,8 @@
56
56
  "access": "public"
57
57
  },
58
58
  "optionalDependencies": {
59
- "@7n/llm-lib-darwin-arm64": "2.9.7",
60
- "@7n/llm-lib-linux-x64": "2.9.7"
59
+ "@7n/llm-lib-darwin-arm64": "2.11.0",
60
+ "@7n/llm-lib-linux-x64": "2.11.0"
61
61
  },
62
62
  "peerDependencies": {
63
63
  "@earendil-works/pi-ai": "~0.80.10",