@maheidem/model-discovery 0.1.0 → 0.6.1

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.
Files changed (4) hide show
  1. package/README.md +197 -22
  2. package/index.ts +1465 -86
  3. package/package.json +9 -3
  4. package/profiles.ts +619 -0
package/README.md CHANGED
@@ -1,15 +1,23 @@
1
1
  # @maheidem/model-discovery
2
2
 
3
- Interactive TUI for discovering and managing local AI model endpoints. Works with llama.cpp, oMLX, Ollama, vLLM, SGLang, LM Studio, and any OpenAI-compatible server.
3
+ Interactive TUI for discovering and managing local AI model endpoints. Works with llama.cpp, oMLX, Ollama, vLLM, SGLang, LM Studio, and other OpenAI-compatible servers.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Auto-detect** server type from headers and model data (no manual config)
8
- - **Read real server-reported configs** — context window, max tokens, reasoning flags, input modalities
9
- - **Fine-tune per-model overrides** — set context window, max tokens, reasoning toggles
10
- - **Multi-endpoint management** — add, scan, and register multiple local servers
11
- - **LLM-callable tool** — the `discover_models` tool lets the agent discover endpoints on your behalf
12
- - **Persistent storage** — providers saved across sessions in `~/.pi/agent/model-discovery.json`
7
+ - **Auto-detect server type** from headers and model data
8
+ - **Read server-reported configuration** — context window, max tokens, reasoning, and vision, with per-model overrides on top
9
+ - **Auto-detect vision-capable models (VLMs)** — from architecture metadata, llama.cpp `--mmproj` args, or oMLX capabilities
10
+ - **Auto-detect reasoning capability** — from `capabilities`, explicit `reasoning` fields, `--reasoning-budget`, and Qwen model names on oMLX
11
+ - **Auto-detect reasoning format** — oMLX servers get `chat_template_kwargs` thinking support automatically
12
+ - **Per-model compatibility** — `supportsDeveloperRole: false` for llama.cpp, oMLX, and Ollama; Qwen thinking format for oMLX
13
+ - **Fine-tune per-model overrides** — context window, max output, reasoning, and vision support
14
+ - **Profile-routed native thinking levels** — Shift-Tab can select complete thinking and sampling presets
15
+ - **Named model presets** — reuse complete thinking/sampling bundles as fixed aliases or adaptive routes
16
+ - **Offline management** — retain the last successful server catalogue for configuration and startup fallback
17
+ - **Authenticated endpoints** — enroll, replace, validate, or clear bearer API keys through masked TUI input
18
+ - **Multi-endpoint management** — add, rename, scan, and remove local model sources
19
+ - **LLM-callable tool** — the `discover_models` tool can register endpoints on the agent's behalf
20
+ - **Persistent storage** in `~/.pi/agent/model-discovery.json`
13
21
 
14
22
  ## Installation
15
23
 
@@ -18,42 +26,209 @@ Interactive TUI for discovering and managing local AI model endpoints. Works wit
18
26
  pi install npm:@maheidem/model-discovery
19
27
 
20
28
  # Via git
21
- pi install git:github.com/Maheidem/model-discovery@v0.1.0
29
+ pi install git:github.com/Maheidem/model-discovery@v0.6.1
22
30
  ```
23
31
 
24
32
  ## Usage
25
33
 
26
- ### Interactive UI
34
+ Run `/discover` in Pi to open the management TUI:
27
35
 
28
- Run `/discover` in pi to open the management TUI:
36
+ - **Add endpoint** enter a URL, choose anonymous or API-key authentication, probe it, review models, and register
37
+ - **Re-scan** — refresh models reported by an existing endpoint
38
+ - **Edit model** — override context, max output, reasoning, or vision support
39
+ - **Manage profiles** — create, edit, rename, or delete named variants
40
+ - **Rename source** — change the provider name shown by `/model`
41
+ - **Remove** — unregister and delete an endpoint
29
42
 
30
- - **Add endpoint** enter a URL, probe it, review models, register
31
- - **Scan existing** — re-scan registered endpoints for fresh model lists
32
- - **Edit per-model** — override context window, max tokens, reasoning flags
33
- - **Remove** — unregister and delete saved endpoints
43
+ You can jump directly into adding an endpoint:
34
44
 
35
- ### With arguments
45
+ ```text
46
+ /discover http://192.168.1.100:8080
47
+ ```
48
+
49
+ Enrollment explicitly asks whether the endpoint is anonymous or requires an API key. API-key input is masked and is sent as `Authorization: Bearer <key>` for both `/v1/models` discovery and inference. The key is stored unencrypted in `~/.pi/agent/model-discovery.json`; the extension writes that file atomically with owner-only (`0600`) permissions. Use **Authentication** on an existing endpoint to replace, validate, or clear its key without losing the cached catalogue.
50
+
51
+ The LLM-callable tool remains available:
36
52
 
53
+ ```text
54
+ discover_models(url="http://192.168.1.100:8080", providerName="my-llama")
37
55
  ```
38
- /discover http://192.168.1.100:8080 # jump straight to adding this endpoint
56
+
57
+ The tool also accepts `apiKey`, but literal tool arguments may be retained in the agent session. Prefer the masked `/discover` flow for secrets.
58
+
59
+ ## How model settings are detected
60
+
61
+ Every field is read from what the server actually reports, first value found wins:
62
+
63
+ - **Context window** — `context_length` → `context_window` → `max_model_len` → `max_context_len` → `max_context_length` → llama.cpp `--ctx-size` (args or preset) → `meta.n_ctx` for loaded models → the source's default context window → `128000`
64
+ - **Max output tokens** — `max_tokens` → `max_output_tokens` → `max_completion_tokens` → llama.cpp `--n-predict` → the source's default → `16384`
65
+ - **Reasoning** — `capabilities` containing `reasoning` → an explicit `reasoning` field → llama.cpp `--reasoning-budget` ≠ 0 → Qwen model names on oMLX (when the server reports nothing)
66
+ - **Vision** — `architecture.input_modalities` (vLLM, SGLang), vision-specific architecture keys (`vision_config`, `vision_model`, `mm_proj`, `multi_modal_projector`), llama.cpp `--mmproj`/`--vision` args or a preset name mentioning mmproj/vision, and oMLX `capabilities` containing `vision`, `image`, or `multimodal`
67
+
68
+ Detected vision-capable models get `input: ["text", "image"]`, so Pi accepts image input for them. The source defaults and every detection can be corrected per model with **Edit model**.
69
+
70
+ ### Compatibility settings
71
+
72
+ The extension attaches `compat` to each registered model (Pi does not merge provider-level compat into individual models):
73
+
74
+ - llama.cpp, oMLX, Ollama: `supportsDeveloperRole: false`
75
+ - oMLX: `thinkingFormat: "qwen-chat-template"` and `supportsReasoningEffort: true` for base models; fixed and adaptive profile aliases carry their own complete `chat_template_kwargs` independently
76
+
77
+ ### Model list display
78
+
79
+ Each model shows `ctx <window> · max <tokens> · <source>`, where source is `server args` for a live llama.cpp process and `api` for other backends. Flags: `[vision]`, `[reasoning]`, `[reasoning?]` (undetermined and not overridden), `[loaded]` (llama.cpp, currently in memory), and `(edited)` when overrides are present.
80
+
81
+ ## Native thinking levels
82
+
83
+ For reasoning-capable Qwen models on oMLX, the base model and sampling-only profiles translate Pi's native Shift-Tab level into request-scoped `chat_template_kwargs`:
84
+
85
+ | Pi level | `enable_thinking` | Qwen `reasoning_effort` |
86
+ | --- | --- | --- |
87
+ | `off` | `false` | omitted |
88
+ | `minimal`, `low` | `true` | `low` |
89
+ | `medium` | `true` | `medium` |
90
+ | `high`, `xhigh`, `max` | `true` | `xhigh` |
91
+
92
+ `preserve_thinking` remains `true`. Fixed-thinking profiles intentionally stay locked to their configured state or effort, while profiles containing only sampling values inherit native Shift-Tab behavior.
93
+
94
+ ### Explicit complete-profile routing
95
+
96
+ Adaptive routing is opt-in and separate from ordinary presets. Creating presets never changes the base model or another alias. In **Thinking & presets**, configure an adaptive alias and explicitly choose a preset for every Pi level. The conventional four-preset helper expands this layout:
97
+
98
+ | Pi level | Selected preset |
99
+ | --- | --- |
100
+ | `off` | instruct/off preset |
101
+ | `minimal`, `low` | low preset |
102
+ | `medium` | medium preset |
103
+ | `high`, `xhigh`, `max` | xhigh preset |
104
+
105
+ The adaptive alias replaces all profile-controlled sampling fields and `chat_template_kwargs` on every request while retaining the same physical server model and conversation. Multiple presets may use the same reasoning effort because the mapping chooses by preset name rather than inference. The base model, sampling-only aliases, and fixed aliases retain their own behavior.
106
+
107
+ The TUI supports cloning presets, hiding preset aliases from `/model`, editing individual level mappings, previewing exact request payloads, disabling routing while preserving its map, and removing the adaptive alias without deleting presets. The footer shows `preset: <slug>` for an adaptive alias and `fixed preset: <slug>` for a fixed alias.
108
+
109
+ Example persisted routing:
110
+
111
+ ```json
112
+ {
113
+ "modelProfileRouting": {
114
+ "Qwen3.8-27B": {
115
+ "enabled": true,
116
+ "aliasSlug": "thinking",
117
+ "levels": {
118
+ "off": "instruct",
119
+ "minimal": "thinking-low",
120
+ "low": "thinking-low",
121
+ "medium": "thinking-medium",
122
+ "high": "thinking-xhigh",
123
+ "xhigh": "thinking-xhigh",
124
+ "max": "thinking-xhigh"
125
+ }
126
+ }
127
+ }
128
+ }
39
129
  ```
40
130
 
41
- ### LLM Tool
131
+ ## Named profiles
42
132
 
43
- The `discover_models` tool can be called by the agent:
133
+ Presets with `exposeAsModel` omitted or `true` appear as fixed models under the same provider. Set `exposeAsModel: false` to keep a preset available to adaptive routing without cluttering `/model`. Given a server model named `Qwen3.8-27B` and a visible preset named `xhigh`, `/model` shows both:
44
134
 
135
+ ```text
136
+ Qwen3.8-27B
137
+ Qwen3.8-27B@xhigh
45
138
  ```
46
- discover_models(url="http://localhost:8080", providerName="my-llama", apiKey="optional-key")
139
+
140
+ The profile request still targets the real server model. For example:
141
+
142
+ ```json
143
+ {
144
+ "modelProfiles": {
145
+ "Qwen3.8-27B": [
146
+ {
147
+ "slug": "xhigh",
148
+ "chatTemplateKwargs": {
149
+ "enable_thinking": true,
150
+ "reasoning_effort": "xhigh",
151
+ "preserve_thinking": false
152
+ },
153
+ "exposeAsModel": false,
154
+ "sampling": {
155
+ "temperature": 0.7,
156
+ "topP": 0.9,
157
+ "topK": 20,
158
+ "minP": 0.05,
159
+ "repetitionPenalty": 1.05,
160
+ "presencePenalty": 0,
161
+ "frequencyPenalty": 0
162
+ }
163
+ }
164
+ ]
165
+ }
166
+ }
47
167
  ```
48
168
 
169
+ Supported thinking values are:
170
+
171
+ - `enable_thinking`: `true` or `false`
172
+ - `reasoning_effort`: `"low"`, `"medium"`, or `"xhigh"`
173
+ - `preserve_thinking`: `true` or `false`
174
+
175
+ Supported sampling values are:
176
+
177
+ - `temperature`: `0–2`; `0` is greedy
178
+ - `topP`: `0–1`; `1` disables top-p filtering
179
+ - `topK`: integer `>= 0`; omit it to keep the backend-specific default
180
+ - `minP`: `0–1`; `0` disables min-p filtering
181
+ - `repetitionPenalty`: `> 0`; `1` disables it
182
+ - `presencePenalty`: `-2–2`; `0` disables it
183
+ - `frequencyPenalty`: `-2–2`; `0` disables it
184
+
185
+ The extension translates these backend-neutral storage names to top-level request fields such as `top_p`, `top_k`, `min_p`, `presence_penalty`, and `frequency_penalty`. Repetition penalty is sent as:
186
+
187
+ - `repeat_penalty` for llama.cpp and LM Studio
188
+ - `repetition_penalty` for oMLX, vLLM, and SGLang
189
+ - `repetition_penalty` as a best-effort fallback for Ollama and unknown OpenAI-compatible servers
190
+
191
+ A configured value is sent exactly. Fixed thinking values take precedence over Pi's current `/think` level, while fixed sampling values take precedence over Pi/request defaults. When every thinking value is omitted, the profile inherits the base model's native Shift-Tab behavior; when any thinking value is configured, only that profile's configured thinking keys are sent. Omitted sampling keys are not sent, leaving them to the server/model default. Profiles may contain thinking values, sampling values, or both. The base model remains independently selectable.
192
+
193
+ Sampling support still depends on the target server. In particular, Ollama's current OpenAI-compatible chat endpoint does not expose `top_k`, `min_p`, or a dedicated repetition-penalty field and may ignore those fallback keys. Omit unsupported controls to retain that backend's defaults.
194
+
195
+ If Pi has an `enabledModels` scope, press **Tab** in `/model` to switch from scoped models to all models, or add the profile alias to `enabledModels`.
196
+
197
+ Profiles are retained if a model temporarily disappears during a re-scan.
198
+
199
+ ## Offline resilience
200
+
201
+ Every successful live scan atomically persists the raw model catalogue as the source's last known-good cache. Saved sources are scanned independently and concurrently at startup. If one source is offline, times out, rejects its credentials, or returns a malformed response:
202
+
203
+ - its cached base models, fixed aliases, and adaptive aliases remain registered;
204
+ - its overrides, presets, and routing remain editable through `/discover`;
205
+ - a failed or empty response never replaces the last known-good cache;
206
+ - the TUI shows the latest failure and time of the last successful scan; and
207
+ - other healthy sources continue loading normally.
208
+
209
+ `Re-scan all` does not unregister a provider before a replacement catalogue has been validated. A source with no previous successful scan is reported as unavailable without affecting any other source. The cache preserves discovery and configuration during an outage; actual inference still requires the model source to become reachable again.
210
+
211
+ Legacy implicit routing created by early v0.6 development builds is migrated once: its sampling-only adaptive alias becomes an explicit router with the same model ID, and its concrete presets are retained. Future presets never activate routing implicitly.
212
+
49
213
  ## Storage
50
214
 
51
- Discovered providers are persisted in `~/.pi/agent/model-discovery.json`.
215
+ Discovered providers, cached catalogues, model overrides, presets, and explicit routing maps are persisted in:
216
+
217
+ ```text
218
+ ~/.pi/agent/model-discovery.json
219
+ ```
52
220
 
53
221
  ## Requirements
54
222
 
55
- - pi coding agent with TUI support
56
- - Access to OpenAI-compatible model servers on your network
223
+ - Pi coding agent **0.84.0 or newer** (`samplingParams` support is required for model aliases)
224
+ - TUI support
225
+ - Network access to an OpenAI-compatible model server
226
+
227
+ ## Development
228
+
229
+ ```bash
230
+ npm test
231
+ ```
57
232
 
58
233
  ## License
59
234