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.
- {laya_cli-0.1.0 → laya_cli-0.2.1}/PKG-INFO +67 -1
- {laya_cli-0.1.0 → laya_cli-0.2.1}/README.md +66 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/pyproject.toml +1 -1
- {laya_cli-0.1.0 → laya_cli-0.2.1}/src/laya_cli/__init__.py +1 -1
- {laya_cli-0.1.0 → laya_cli-0.2.1}/src/laya_cli/cli.py +508 -67
- laya_cli-0.2.1/src/laya_cli/daemon.py +445 -0
- laya_cli-0.2.1/tests/test_daemon.py +243 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/uv.lock +3 -3
- {laya_cli-0.1.0 → laya_cli-0.2.1}/.github/workflows/ci.yml +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/.github/workflows/publish.yml +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/.gitignore +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/.python-version +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/LICENSE +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/TASK.md +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/tests/__init__.py +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/tests/conftest.py +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/tests/test_classify.py +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/tests/test_cli.py +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/tests/test_evaluate.py +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/tests/test_filter.py +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/tests/test_predict.py +0 -0
- {laya_cli-0.1.0 → laya_cli-0.2.1}/tests/test_questions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: laya-cli
|
|
3
|
-
Version: 0.1
|
|
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
|