Skip to content

nativ cli - #228

Open
Lazarus-931 wants to merge 10 commits into
mainfrom
feat-nativ-cli
Open

Lazarus-931 wants to merge 10 commits into
mainfrom
feat-nativ-cli

Conversation

@Lazarus-931

@Lazarus-931 Lazarus-931 commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Commands

  • run — one-shot completion (streams; --system, --image, --json, stdin)
  • chat — interactive REPL (/model, /system, /reset, """ multiline)
  • serve / stop / status — manage the bundled server (serve -d waits until ready)
  • models list | use | pull | rm — list loaded + locally-cached models, set default, download, remove
  • embed — text embeddings
  • image — image generation
  • transcribe — speech-to-text
  • audio speak — text-to-speech (the audio group grows into separation/enhancement/sfx as the engine exposes those endpoints)
  • config show | set | path — the app writes cli.json; this configures the CLI standalone
  • agent — a full reference for coding agents (markdown or --json)

Design

  • Contract = the engine, not new logic. Inference goes through the server's OpenAI-compatible API; the CLI carries only a thin HTTP client, no reimplementation of engine behavior. Per-capability models (chat/embedding/image/stt/tts) resolve flag → env → cli.json → default.
  • Decoupled. The only app touchpoint is cli.json, so Nativ internals can change without breaking the CLI, and the same binary works against a local or remote server.
  • Tested. Unit tests cover SSE parsing, multipart framing, and config resolution; verified end-to-end against a real mlx-vlm server (chat/embeddings/models/config all green).

Direction (follow-ups)
Make the inference commands server-aware with a local fallback — reuse the running server when present, otherwise cold-load via the bundled engine CLI — so the CLI works whether or not the app is open. Offline tooling (convert) will shell straight to the engine rather than being reimplemented.


Note on the agent command: it exists so a coding agent can learn the whole CLI in one cheap call instead of probing --help or the repo. Quick measurement — two fresh agents asked to produce a full usage guide, one told about nativ agent, one left to figure it out:

Without agent With agent
Tokens ~38,400 ~18,600
Tool calls 9 1
Wall time 172 s 48 s
Result reached a wrong conclusion correct + complete

≈2× fewer tokens, one call instead of nine, and it avoided a mistaken finding. (n=1 per side — a broader multi-model run is planned.)

@Lazarus-931
Lazarus-931 marked this pull request as ready for review August 8, 2026 14:10
@Blaizzy

Blaizzy commented Aug 9, 2026

Copy link
Copy Markdown
Owner

transcribe
audio speak

The resulting api arg should be:

audio --task [tts, stt, sts, vad, lid]

Where the tasks are the same as in mlx-audio.

@Blaizzy

Blaizzy commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Regarding the agent, thanks for sharing the results, it does indeed provide great time savings!

Could you share the inputs and traces as well?

@Lazarus-931

Lazarus-931 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

Reran as a clean A/B — the difference is baked into the binary, not the prompt.

Reproduction

Two builds of the same commit; in one, the agent command is removed entirely (no trace of it in --help). Two fresh agents (independent contexts, same model) each get the identical prompt — no hint about agent, no restriction:

Learn how to use the nativ CLI (binary: <binary>), then write a short usage guide covering all its commands.

So the only variable is whether agent exists and is self-discoverable via --help. Token usage is measured by the runtime.

Results

no agent agent present (no hint)
Tokens 44,623 26,612
Tool calls 13 8
Wall time 140 s 102 s

With agent in the binary — found on its own via --help, never hinted — the agent used ~40% fewer tokens and fewer tool calls. Without it, the agent fell back to reading --help across every subcommand and then the source files.

n=1 per side (agent behavior is stochastic), but the direction is consistent across runs: a self-documenting agent command is a cheap entry point for coding agents, with no downside when it isn't used.

@Blaizzy

Blaizzy commented Aug 9, 2026

Copy link
Copy Markdown
Owner

The tests fail

Also, have you updated to wrap the mlx-vlm CLI tools as we spoke or this is more of temporary solution till we build it in mlx-vlm?

@Lazarus-931

Copy link
Copy Markdown
Collaborator Author

The tests fail

Also, have you updated to wrap the mlx-vlm CLI tools as we spoke or this is more of temporary solution till we build it in mlx-vlm?

this is a temp solution, but i think i can push upstream pr so i'll do that before changing this to full supported wrap

A standalone Swift package (cli/) that drives the local mlx-vlm server over its
OpenAI-compatible API from the terminal: run/chat/serve/status/stop, models
list/use/pull/rm, embed, image, transcribe. API-first and decoupled from the
app internals via a small cli.json handshake; each command is one file in a
registry. Builds with swift build. See cli/README.md.
… richer list/chat/run, tests

Fold in the improvement pass: embedding/image/stt models resolved separately
(env + cli.json, falling back to the chat model); a config command to read/write
cli.json standalone; serve -d waits until the server answers; models list merges
loaded with locally-cached (search path + HF hub cache); run --json for
scripting; chat slash commands (/model, /system, /reset, /help) + multiline; an
agent command that prints a full reference (markdown or JSON); a shared URLSession
with an idle timeout; SSE + multipart extracted as unit-tested pure helpers.
/v1/audio/speech-backed `nativ speak`; ttsModel / NATIV_TTS_MODEL config with
fallback to the chat model; config set --tts-model; agent + README + test.
Idle timeout resets per chunk, so it only fires on a silent server; large
models with long prompts can take minutes to first token, so 120s was too tight.
TTS is one kind of audio-out; group it under `nativ audio` so other tasks
(separation, enhancement, sfx) can land as thin reflections of future server
endpoints. ttsModel config unchanged; agent reference + README updated.
…back)

run reuses the running server if up, else cold-loads via the bundled engine
(python3 -m mlx_vlm.generate --no-verbose), so it works with the app closed.
EngineProcess locates the bundled python3 (NATIV_ENGINE_BIN override), sharing
the app-bundle lookup with ServerProcess. --json still needs the server.
Per review: fold transcribe (stt) and speak (tts) into one `nativ audio` command
driven by --task, matching mlx-audio's task taxonomy. tts and stt route to the
server; sts/vad/lid are accepted names that error until the server exposes them.
Removes the standalone transcribe command and the audio speak subcommand.
@Lazarus-931
Lazarus-931 marked this pull request as draft August 10, 2026 03:06
mlx-vlm's server-aware generate treats --base-url as opt-in and errors if the
URL is unreachable, so passing it unconditionally broke local fallback when the
server is down. Gate it on isUp(): reuse the server when up, otherwise invoke
the engine without --base-url so it loads the model locally.
@Lazarus-931
Lazarus-931 marked this pull request as ready for review August 10, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants