@7n/llm-lib 2.6.2 → 2.7.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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.7.0] - 2026-07-16
4
+
5
+ ### Added
6
+
7
+ - `runAcpAgent`/`resolveModel`/`oneShotLocalCloud` (`@7n/llm-lib/acp`) — napi-міст до Rust-крейта `llm_cascade` (`llm-lib/crates/llm-cascade-napi`): ACP-виклик `cursor`/`codex`, каскад тирів і local/cloud chat-виклик в одному процесі, без повторної реалізації протоколу в JS
8
+
3
9
  ## [2.6.2] - 2026-07-14
4
10
 
5
11
  ### Added
package/lib/acp.mjs ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * ACP (Agent Client Protocol, Zed) — доступ до `cursor`/`codex` через
3
+ * особисту підписку (вже залогінений локально CLI), не API-ключ.
4
+ *
5
+ * Тонкий JS-клієнт до Rust-крейта `llm_cascade::acp` через napi FFI
6
+ * in-process (`llm-lib/crates/llm-cascade-napi`) — жодного власного
7
+ * ACP JSON-RPC/`ClientSideConnection` тут; уся протокольна логіка (спавн
8
+ * агента, `session/prompt`, автоапрув `session/request_permission`) живе
9
+ * в Rust, разом з watchdog-поведінкою на мертвий/незапущений дочірній процес.
10
+ *
11
+ * `claude` тут немає — Rust-крейт моделює лише `cursor`/`codex`
12
+ * (`AcpAgentKind`); deprecated `claude`-раннер лишається окремим
13
+ * JS-шимом у `@7n/rules` (`npm/scripts/lib/acp-runner.mjs`).
14
+ */
15
+ import { loadNative } from './internal/native.mjs'
16
+
17
+ /**
18
+ * Один виклик через ACP-агента з особистою підпискою.
19
+ * @param {'cursor' | 'codex'} kind провайдер
20
+ * @param {string} prompt промпт
21
+ * @param {string} cwd робочий каталог сесії агента (каталог проєкту-викликача)
22
+ * @param {{ native?: { oneShotAcp: (kind: string, prompt: string, cwd: string) => Promise<string> } }} [deps] інжект для тестів
23
+ * @returns {Promise<string>} повний текст відповіді до кінця ходу
24
+ */
25
+ export function runAcpAgent(kind, prompt, cwd, deps = {}) {
26
+ const native = deps.native ?? loadNative()
27
+ return native.oneShotAcp(kind, prompt, cwd)
28
+ }
@@ -0,0 +1,31 @@
1
+ ---
2
+ type: JS Module
3
+ title: acp.mjs
4
+ resource: llm-lib/lib/acp.mjs
5
+ docgen:
6
+ crc: 5c32e90c
7
+ model: openai-codex/gpt-5.4-mini
8
+ score: 100
9
+ issues: judge:inaccurate:0.97
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ Файл надає тонкий JS-доступ до `cursor` або `codex` через публічну `runAcpAgent`, покладаючись на вже авторизовану локальну CLI-сесію без API-ключів. Уся ACP-логіка живе в нативному Rust-шарі `llm_cascade::acp`, який викликається in-process через `napi FFI` у `llm-lib/crates/llm-cascade-napi`; тут немає власного `ClientSideConnection` чи JSON-RPC. Саме Rust запускає агента, обробляє `session/prompt`, автоматично погоджує `session/request_permission` і стежить за живістю дочірнього процесу. Крейт підтримує лише `cursor`/`codex`; `claude`-runner лишається окремим JS-шимом у `@7n/rules` (`npm/scripts/lib/acp-runner.mjs`).
16
+
17
+ ## Поведінка
18
+
19
+ 1. `runAcpAgent` запускає один ACP-хід для `cursor` або `codex` через вже авторизовану локальну CLI-сесію, без API-ключів.
20
+ 2. Вона звертається до нативного Rust-шару `llm_cascade::acp`, який бере на себе весь протокол взаємодії: старт агента, обмін `session/prompt`, автоапрув запитів на дозвіл і контроль живості дочірнього процесу.
21
+ 3. Вона передає робочий каталог поточного проєкту як контекст сесії, щоб агент працював у межах каталогу викликача.
22
+ 4. Вона повертає повний текст відповіді агента за один хід.
23
+ 5. Вона не виконує власну протокольну логіку, не працює з `claude`, і не покладається на `ClientSideConnection`; підтримка `claude` живе окремо в JS-шимі `npm/scripts/lib/acp-runner.mjs`.
24
+
25
+ ## Публічний API
26
+
27
+ - runAcpAgent — запускає один запит через ACP-агента з власною підпискою
28
+
29
+ ## Гарантії поведінки
30
+
31
+ - Read-only: не виконує операцій запису (ФС/БД).
package/lib/docs/index.md CHANGED
@@ -4,22 +4,21 @@ title: llm-lib/lib
4
4
  resource: llm-lib/lib/
5
5
  ---
6
6
 
7
- # llm-lib/lib
8
-
9
- Публічні модулі пакета `@7n/llm-lib` (див. README пакета; спека
10
- docs/specs/2026-07-05-llm-lib-extraction-spec.md).
11
-
12
7
  | Файл | Тип |
13
8
  | ----------------------------------------- | --------- |
9
+ | [acp.mjs](acp.md) | JS Module |
14
10
  | [agent-fix.mjs](agent-fix.md) | JS Module |
15
11
  | [agent-skill.mjs](agent-skill.md) | JS Module |
12
+ | [anchored-edit.mjs](anchored-edit.md) | JS Module |
16
13
  | [body-capture.mjs](body-capture.md) | JS Module |
17
14
  | [chain.mjs](chain.md) | JS Module |
18
15
  | [chains-report.mjs](chains-report.md) | JS Module |
16
+ | [harness.mjs](harness.md) | JS Module |
19
17
  | [model-tiers.mjs](model-tiers.md) | JS Module |
20
18
  | [one-shot.mjs](one-shot.md) | JS Module |
21
19
  | [prompt-budget.mjs](prompt-budget.md) | JS Module |
22
20
  | [telemetry-store.mjs](telemetry-store.md) | JS Module |
23
21
  | [trace.mjs](trace.md) | JS Module |
22
+ | [web-tools.mjs](web-tools.md) | JS Module |
24
23
  | [with-timeout.mjs](with-timeout.md) | JS Module |
25
24
  | [write-guard.mjs](write-guard.md) | JS Module |
@@ -12,4 +12,5 @@ resource: llm-lib/lib/internal/
12
12
  | [compress-context.mjs](compress-context.md) | JS Module |
13
13
  | [max-tokens.mjs](max-tokens.md) | JS Module |
14
14
  | [memory-guard.mjs](memory-guard.md) | JS Module |
15
+ | [native.mjs](native.md) | JS Module |
15
16
  | [registry.mjs](registry.md) | JS Module |
@@ -0,0 +1,30 @@
1
+ ---
2
+ type: JS Module
3
+ title: native.mjs
4
+ resource: llm-lib/lib/internal/native.mjs
5
+ docgen:
6
+ crc: 205418d5
7
+ model: openai-codex/gpt-5.5
8
+ score: 100
9
+ issues: judge:inaccurate:0.98
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ Файл знаходить і завантажує native-аддон `llm-cascade`, щоб JavaScript-код використовував Rust-ядро через napi-артефакт. `resolveNativeAddon` визначає шлях за єдиним порядком: явний override `N_LLM_LIB_NATIVE_ADDON`, platform-підпакет `@7n/llm-lib-<platform>-<arch>` з артефактом `llm-cascade-napi.<triple>.node`, dev-fallback у `target/release|debug/` після `cargo build -p llm-cascade-napi` або вивід у `llm-lib/crates/llm-cascade-napi/`. `loadNative` завантажує знайдений аддон через `process.dlopen` і кешує результат у межах процесу. На непідтриманих платформах запуск зупиняється зрозумілою помилкою без JS-fallback.
16
+
17
+ ## Поведінка
18
+
19
+ - `resolveNativeAddon` визначає шлях до native-аддона `llm-cascade`: спершу бере явний override, далі шукає platform-підпакет, потім локальні dev-збірки; для непідтриманої або незібраної платформи завершується зрозумілою помилкою без JS-fallback.
20
+ - `loadNative` завантажує native-аддон один раз за процес і повертає закешовані exports для повторних викликів.
21
+
22
+ ## Публічний API
23
+
24
+ - resolveNativeAddon — знаходить файл native addon `llm-cascade` для поточного середовища або тестових підмін.
25
+ - loadNative — повертає native addon із кешу, щоб завантажувати його лише один раз за час роботи процесу.
26
+
27
+ ## Гарантії поведінки
28
+
29
+ - Read-only: не виконує операцій запису (ФС/БД).
30
+ - Кешує результати в межах одного прогону.
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Loader napi-аддона `llm-cascade` (Rust-ядро `llm-lib/crates/llm-cascade-napi`
3
+ * → `llm-cascade`) — за зразком `mt/npm/lib/core/native.mjs`.
4
+ *
5
+ * Порядок пошуку:
6
+ * 1. N_LLM_LIB_NATIVE_ADDON — явний override шляху до аддона (dev / CI / тести).
7
+ * 2. Platform-підпакет `@7n/llm-lib-<platform>-<arch>` (napi-артефакт
8
+ * `llm-cascade-napi.<triple>.node`).
9
+ * 3. Dev-fallback: `<repoRoot>/target/release|debug/` (сирий cdylib з
10
+ * `cargo build -p llm-cascade-napi`) та вивід `napi build` у
11
+ * `llm-lib/crates/llm-cascade-napi/`.
12
+ * 4. Інакше — зрозуміла помилка з підказкою.
13
+ *
14
+ * Аддон завантажується через `process.dlopen` — працює і для `.node`, і для
15
+ * сирих cdylib (`.dylib`/`.so`). Результат кешується (одне завантаження на процес).
16
+ * Без JS-fallback на неоголошеній платформі — hard error, свідома межа v1
17
+ * (darwin-arm64, linux-x64), не регресія.
18
+ */
19
+ import { existsSync } from 'node:fs'
20
+ import { createRequire } from 'node:module'
21
+ import { dirname, join } from 'node:path'
22
+ import process, { arch as osArch, env as procEnv, platform as osPlatform } from 'node:process'
23
+ import { fileURLToPath } from 'node:url'
24
+
25
+ const require = createRequire(import.meta.url)
26
+ const HERE = dirname(fileURLToPath(import.meta.url))
27
+ /** Корінь репо: llm-lib/lib/internal → up 3. */
28
+ const REPO_ROOT = join(HERE, '..', '..', '..')
29
+
30
+ /** Підтримувані platform-arch → napi-суфікс артефакта (v1: darwin-arm64, linux-x64). */
31
+ const NAPI_SUFFIXES = {
32
+ 'darwin-arm64': 'darwin-arm64',
33
+ 'linux-x64': 'linux-x64-gnu'
34
+ }
35
+
36
+ /** @type {Record<string, unknown> | null} */
37
+ let cached = null
38
+
39
+ /**
40
+ * Завантажує аддон за шляхом через process.dlopen.
41
+ * @param {string} p шлях до .node / .dylib / .so
42
+ * @returns {Record<string, unknown>} exports аддона
43
+ */
44
+ function dlopenAddon(p) {
45
+ const mod = { exports: {} }
46
+ process.dlopen(mod, p)
47
+ return mod.exports
48
+ }
49
+
50
+ /**
51
+ * Ім'я cdylib-файлу для платформи (вивід `cargo build -p llm-cascade-napi`).
52
+ * @param {string} platform process.platform
53
+ * @returns {string} ім'я бібліотеки
54
+ */
55
+ function cdylibName(platform) {
56
+ return platform === 'darwin' ? 'libllm_cascade_napi.dylib' : 'libllm_cascade_napi.so'
57
+ }
58
+
59
+ /**
60
+ * Резолвить шлях до napi-аддона `llm-cascade`.
61
+ * @param {{
62
+ * env?: Record<string, string | undefined>,
63
+ * platform?: string,
64
+ * arch?: string,
65
+ * existsSync?: (p: string) => boolean,
66
+ * requireResolve?: (id: string) => string,
67
+ * repoRoot?: string
68
+ * }} [deps] ін'єкції для тестів
69
+ * @returns {string} шлях до файлу аддона
70
+ */
71
+ export function resolveNativeAddon(deps = {}) {
72
+ const env = deps.env ?? procEnv
73
+ const platform = deps.platform ?? osPlatform
74
+ const arch = deps.arch ?? osArch
75
+ const exists = deps.existsSync ?? existsSync
76
+ const requireResolve = deps.requireResolve ?? (id => require.resolve(id))
77
+ const repoRoot = deps.repoRoot ?? REPO_ROOT
78
+
79
+ // 1. Явний override.
80
+ const override = env.N_LLM_LIB_NATIVE_ADDON
81
+ if (override) return override
82
+
83
+ const key = `${platform}-${arch}`
84
+ const suffix = NAPI_SUFFIXES[key]
85
+
86
+ // 2. Platform-підпакет.
87
+ if (suffix) {
88
+ try {
89
+ return requireResolve(`@7n/llm-lib-${key}/llm-cascade-napi.${suffix}.node`)
90
+ } catch {
91
+ // не встановлено — пробуємо dev-fallback
92
+ }
93
+ }
94
+
95
+ // 3. Dev-fallback: cargo-збірка (сирий cdylib) або вивід napi build.
96
+ const candidates = Array.from(['release', 'debug'], profile =>
97
+ join(repoRoot, 'target', profile, cdylibName(platform))
98
+ )
99
+ if (suffix) {
100
+ candidates.push(join(repoRoot, 'llm-lib', 'crates', 'llm-cascade-napi', `llm-cascade-napi.${suffix}.node`))
101
+ }
102
+ for (const candidate of candidates) {
103
+ if (exists(candidate)) return candidate
104
+ }
105
+
106
+ // 4. Помилка з підказкою.
107
+ throw new Error(
108
+ `llm-cascade native addon: немає збірки для "${key}". ` +
109
+ `Постав N_LLM_LIB_NATIVE_ADDON=/шлях/до/аддона, додай підпакет @7n/llm-lib-${key}, ` +
110
+ `або збери локально: cargo build --release -p llm-cascade-napi`
111
+ )
112
+ }
113
+
114
+ /**
115
+ * Кешований доступ до аддона (одне завантаження на процес).
116
+ * @param {{ resolve?: () => string, dlopen?: (p: string) => Record<string, unknown> }} [deps] ін'єкції
117
+ * @returns {Record<string, unknown>} exports аддона (oneShotAcp, resolveModel, oneShotLocalCloud)
118
+ */
119
+ export function loadNative(deps = {}) {
120
+ if (cached === null) {
121
+ const path = (deps.resolve ?? resolveNativeAddon)()
122
+ cached = (deps.dlopen ?? dlopenAddon)(path)
123
+ }
124
+ return cached
125
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@7n/llm-lib",
3
- "version": "2.6.2",
3
+ "version": "2.7.0",
4
4
  "description": "Тонкий шар роботи з LLM (локальні omlx + хмарні провайдери) поверх pi: model tiers, one-shot, agentic-раннери, write-guard, trace, telemetry, prompt-budget",
5
5
  "keywords": [
6
6
  "nitra",
@@ -36,6 +36,7 @@
36
36
  "./anchored-edit": "./lib/anchored-edit.mjs",
37
37
  "./web-tools": "./lib/web-tools.mjs",
38
38
  "./model-tiers": "./lib/model-tiers.mjs",
39
+ "./acp": "./lib/acp.mjs",
39
40
  "./chain": "./lib/chain.mjs",
40
41
  "./chains-report": "./lib/chains-report.mjs",
41
42
  "./one-shot": "./lib/one-shot.mjs",