laya-cli 0.1.0__tar.gz → 0.2.1__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: laya-cli
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: Ergonomic CLI for Laya — typed decisions for humans and AI agents (predict, batch, presets, shortlist, router)
5
5
  Project-URL: Homepage, https://github.com/MIt9/laya-cli
6
6
  Project-URL: Repository, https://github.com/MIt9/laya-cli.git
@@ -51,6 +51,7 @@ A modern, high-performance CLI for [Laya](https://github.com/NandhaKishorM/laya)
51
51
  * 🔍 **Preset Library**: `triage` / `email` / `guard` / `moderation` / `router` — direct `laya.*_questions()` passthrough, mergeable with `--questions file.json` and `--questions-inline`
52
52
  * 📦 **Streaming Batch Mode**: `classify`/`predict --input` loads model **once** + warmup, streams JSONL (`--state-field` verbatim, no silent `(photographer: Name)` injection)
53
53
  * 🔧 **Post-Filter & Eval**: `filter --where "on_topic>=0.4" --sort -on_topic` and `evaluate` (accuracy, passing @ threshold, precision, escalation rate)
54
+ * ⚡ **Resident Daemon (optional)**: `laya-cli serve` keeps model in RAM — `predict`/`classify`/`evaluate` auto-hit `127.0.0.1` and skip 10-35s `laya.load()` on repeated calls (hash → `~/.cache/laya-cli/daemons/<hash>.json`, idle-timeout 1800s)
54
55
 
55
56
  ---
56
57
 
@@ -158,6 +159,71 @@ laya-cli info # python/torch/cuda/mps + cache
158
159
  laya-cli evaluate --questions questions.json --labeled labeled.jsonl --label-field label --threshold 0.5
159
160
  ```
160
161
 
162
+ ### 4. Resident Daemon Mode (optional, speeds up repeated calls)
163
+
164
+ **Виміряний факт (сесія 2026-09-22, 82 кандидати, MPS):**
165
+
166
+ | етап | час |
167
+ |------|-----|
168
+ | `px` (мережа, 12 запитів) | 9.3s |
169
+ | `laya.load()` (модель у пам'ять) | 10–35s |
170
+ | inference, 82 кандидати | ~10s (~120ms/шт) |
171
+ | `filter` | 0.08s |
172
+
173
+ Для одного пайплайну `px → classify → filter` 35–50s норм. Проблема — коли за сесію кілька разів викликаєш `predict`/`classify`/`evaluate` (підбір `questions.json`: прогнав → подивився → поправив → знову), кожен раз платиш 10–35s за ту саму модель. `laya-cli serve` тримає модель в RAM, наступні виклики летять на `127.0.0.1` (<1ms overhead).
174
+
175
+ #### Транспорт (як у `~/.claude/skills/laya-integration/SKILL.md` "Anything else... HTTP sidecar")
176
+
177
+ HTTP на loopback `127.0.0.1` (не `0.0.0.0`), один потік з `threading.Lock` (SKILL.md: "one GPU serves one forward pass at a time"):
178
+
179
+ - `POST /predict` → `{"state": ..., "questions": {...}, "lang": "...", "shortlist_k": 20}` → те саме що `agent.predict()` (той самий JSON що `laya-cli predict --format json`)
180
+ - `GET /status` → `{"model": "...", "subfolder": "...", "device": "...", "loaded_at": 123..., "idle_seconds": 42, "requests_served": 17, "pid": 12345, "port": 8765}`
181
+ - `POST /shutdown` → graceful stop (лише з localhost, також `serve stop` шле сигнал за pid-файлом)
182
+
183
+ #### Lifecycle
184
+
185
+ ```bash
186
+ # Старт (без --foreground — форк у фон, пише pid+port в ~/.cache/laya-cli/daemons/<hash>.json)
187
+ laya-cli serve --model convaiinnovations/laya --device mps
188
+ laya-cli serve --model convaiinnovations/laya --subfolder multilingual --device cpu --idle-timeout 60
189
+ laya-cli serve --router --foreground --idle-timeout 0 --port 8765 # форграунд для логів, 0=disabled idle
190
+
191
+ # Один daemon = один конфіг (hash(model|subfolder|device|router|lang)), інший конфіг — окремий файл/порт
192
+ laya-cli serve status # дефолтний конфіг (як у predict без прапорців)
193
+ laya-cli serve status --model convaiinnovations/laya --subfolder multilingual --device cpu
194
+ laya-cli serve stop # graceful (POST /shutdown → pid файл видаляється)
195
+ laya-cli serve stop --all # всі daemon-и
196
+ # Також: curl http://127.0.0.1:<port>/status
197
+ ```
198
+
199
+ Перед прийомом запитів — прогрів throwaway `predict` (як у `TASK.md`). `idle-timeout 1800s` дефолт, `--idle-timeout 5` для тесту → daemon сам виходить через 5s без запитів і `serve status` каже `not running`.
200
+
201
+ #### Клієнт (`predict`/`classify`/`evaluate`)
202
+
203
+ Перед `laya.load()` перевіряє `~/.cache/laya-cli/daemons/<hash>.json` для поточного конфігу; якщо файл є і daemon відповідає на `/status` — шле туди, інакше мовчки падає назад на in-process (поведінка `v1` без змін). `--no-daemon` форсує in-process (для відтворюваності/дебагу). Для батчу (`classify`/`predict --input`) — кожен рядок окремий `POST /predict` в циклі (loopback мілісекунди, batch-ендпоінт не потрібен).
204
+
205
+ ```bash
206
+ # AI workflow (повністю автоматичний):
207
+ laya-cli serve --device mps & # один раз на сесію
208
+ laya-cli predict "hello" --preset guard --format json # -> via daemon, без 10s
209
+ laya-cli predict "hello2" --preset guard --format json # -> знову via daemon
210
+ laya-cli serve status # {"loaded_at":..., "requests_served": 2}
211
+ laya-cli predict "hello" --preset guard --no-daemon # форс in-process (знову 10s, для ізоляції)
212
+ laya-cli serve stop
213
+
214
+ # Human tuning loop (типовий):
215
+ laya-cli serve & # фон
216
+ cat candidates.jsonl | laya-cli classify --questions q.json | laya-cli filter --where "on_topic>=0.4" --sort -on_topic # via daemon
217
+ # ...поправив q.json...
218
+ cat candidates.jsonl | laya-cli classify --questions q.json | laya-cli filter ... # знову via daemon, без перезавантаження
219
+ laya-cli serve stop
220
+
221
+ # 5 паралельних predict — не падають, результати не плутаються (серіалізація Lock)
222
+ seq 1 5 | xargs -P5 -I{} laya-cli predict "text {}" --preset guard --format json
223
+ ```
224
+
225
+ **Безпека/межі:** лише `127.0.0.1`, без auth (однокористувацька машина, як у SKILL.md), один потік, stateless крім моделі.
226
+
161
227
  ---
162
228
 
163
229
  ## 🛠 Development
@@ -16,6 +16,7 @@ A modern, high-performance CLI for [Laya](https://github.com/NandhaKishorM/laya)
16
16
  * 🔍 **Preset Library**: `triage` / `email` / `guard` / `moderation` / `router` — direct `laya.*_questions()` passthrough, mergeable with `--questions file.json` and `--questions-inline`
17
17
  * 📦 **Streaming Batch Mode**: `classify`/`predict --input` loads model **once** + warmup, streams JSONL (`--state-field` verbatim, no silent `(photographer: Name)` injection)
18
18
  * 🔧 **Post-Filter & Eval**: `filter --where "on_topic>=0.4" --sort -on_topic` and `evaluate` (accuracy, passing @ threshold, precision, escalation rate)
19
+ * ⚡ **Resident Daemon (optional)**: `laya-cli serve` keeps model in RAM — `predict`/`classify`/`evaluate` auto-hit `127.0.0.1` and skip 10-35s `laya.load()` on repeated calls (hash → `~/.cache/laya-cli/daemons/<hash>.json`, idle-timeout 1800s)
19
20
 
20
21
  ---
21
22
 
@@ -123,6 +124,71 @@ laya-cli info # python/torch/cuda/mps + cache
123
124
  laya-cli evaluate --questions questions.json --labeled labeled.jsonl --label-field label --threshold 0.5
124
125
  ```
125
126
 
127
+ ### 4. Resident Daemon Mode (optional, speeds up repeated calls)
128
+
129
+ **Виміряний факт (сесія 2026-09-22, 82 кандидати, MPS):**
130
+
131
+ | етап | час |
132
+ |------|-----|
133
+ | `px` (мережа, 12 запитів) | 9.3s |
134
+ | `laya.load()` (модель у пам'ять) | 10–35s |
135
+ | inference, 82 кандидати | ~10s (~120ms/шт) |
136
+ | `filter` | 0.08s |
137
+
138
+ Для одного пайплайну `px → classify → filter` 35–50s норм. Проблема — коли за сесію кілька разів викликаєш `predict`/`classify`/`evaluate` (підбір `questions.json`: прогнав → подивився → поправив → знову), кожен раз платиш 10–35s за ту саму модель. `laya-cli serve` тримає модель в RAM, наступні виклики летять на `127.0.0.1` (<1ms overhead).
139
+
140
+ #### Транспорт (як у `~/.claude/skills/laya-integration/SKILL.md` "Anything else... HTTP sidecar")
141
+
142
+ HTTP на loopback `127.0.0.1` (не `0.0.0.0`), один потік з `threading.Lock` (SKILL.md: "one GPU serves one forward pass at a time"):
143
+
144
+ - `POST /predict` → `{"state": ..., "questions": {...}, "lang": "...", "shortlist_k": 20}` → те саме що `agent.predict()` (той самий JSON що `laya-cli predict --format json`)
145
+ - `GET /status` → `{"model": "...", "subfolder": "...", "device": "...", "loaded_at": 123..., "idle_seconds": 42, "requests_served": 17, "pid": 12345, "port": 8765}`
146
+ - `POST /shutdown` → graceful stop (лише з localhost, також `serve stop` шле сигнал за pid-файлом)
147
+
148
+ #### Lifecycle
149
+
150
+ ```bash
151
+ # Старт (без --foreground — форк у фон, пише pid+port в ~/.cache/laya-cli/daemons/<hash>.json)
152
+ laya-cli serve --model convaiinnovations/laya --device mps
153
+ laya-cli serve --model convaiinnovations/laya --subfolder multilingual --device cpu --idle-timeout 60
154
+ laya-cli serve --router --foreground --idle-timeout 0 --port 8765 # форграунд для логів, 0=disabled idle
155
+
156
+ # Один daemon = один конфіг (hash(model|subfolder|device|router|lang)), інший конфіг — окремий файл/порт
157
+ laya-cli serve status # дефолтний конфіг (як у predict без прапорців)
158
+ laya-cli serve status --model convaiinnovations/laya --subfolder multilingual --device cpu
159
+ laya-cli serve stop # graceful (POST /shutdown → pid файл видаляється)
160
+ laya-cli serve stop --all # всі daemon-и
161
+ # Також: curl http://127.0.0.1:<port>/status
162
+ ```
163
+
164
+ Перед прийомом запитів — прогрів throwaway `predict` (як у `TASK.md`). `idle-timeout 1800s` дефолт, `--idle-timeout 5` для тесту → daemon сам виходить через 5s без запитів і `serve status` каже `not running`.
165
+
166
+ #### Клієнт (`predict`/`classify`/`evaluate`)
167
+
168
+ Перед `laya.load()` перевіряє `~/.cache/laya-cli/daemons/<hash>.json` для поточного конфігу; якщо файл є і daemon відповідає на `/status` — шле туди, інакше мовчки падає назад на in-process (поведінка `v1` без змін). `--no-daemon` форсує in-process (для відтворюваності/дебагу). Для батчу (`classify`/`predict --input`) — кожен рядок окремий `POST /predict` в циклі (loopback мілісекунди, batch-ендпоінт не потрібен).
169
+
170
+ ```bash
171
+ # AI workflow (повністю автоматичний):
172
+ laya-cli serve --device mps & # один раз на сесію
173
+ laya-cli predict "hello" --preset guard --format json # -> via daemon, без 10s
174
+ laya-cli predict "hello2" --preset guard --format json # -> знову via daemon
175
+ laya-cli serve status # {"loaded_at":..., "requests_served": 2}
176
+ laya-cli predict "hello" --preset guard --no-daemon # форс in-process (знову 10s, для ізоляції)
177
+ laya-cli serve stop
178
+
179
+ # Human tuning loop (типовий):
180
+ laya-cli serve & # фон
181
+ cat candidates.jsonl | laya-cli classify --questions q.json | laya-cli filter --where "on_topic>=0.4" --sort -on_topic # via daemon
182
+ # ...поправив q.json...
183
+ cat candidates.jsonl | laya-cli classify --questions q.json | laya-cli filter ... # знову via daemon, без перезавантаження
184
+ laya-cli serve stop
185
+
186
+ # 5 паралельних predict — не падають, результати не плутаються (серіалізація Lock)
187
+ seq 1 5 | xargs -P5 -I{} laya-cli predict "text {}" --preset guard --format json
188
+ ```
189
+
190
+ **Безпека/межі:** лише `127.0.0.1`, без auth (однокористувацька машина, як у SKILL.md), один потік, stateless крім моделі.
191
+
126
192
  ---
127
193
 
128
194
  ## 🛠 Development
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "laya-cli"
3
- version = "0.1.0"
3
+ version = "0.2.1"
4
4
  description = "Ergonomic CLI for Laya — typed decisions for humans and AI agents (predict, batch, presets, shortlist, router)"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -1,3 +1,3 @@
1
1
  """laya-cli — streaming JSONL classifier over Laya."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.2.1"