From 39c39e819919d73118cd5df7911a0c0f8e0bc500 Mon Sep 17 00:00:00 2001 From: rltakashige Date: Mon, 30 Mar 2026 14:28:41 +0100 Subject: [PATCH] Integrations helpers (#1810) ## Motivation ## Changes ## Why It Works ## Test Plan ### Manual Testing ### Automated Testing --- dashboard/src/lib/components/HeaderNav.svelte | 68 ++- .../src/lib/components/IntegrationCard.svelte | 52 ++ dashboard/src/lib/components/index.ts | 1 + .../src/routes/integrations/+page.svelte | 577 ++++++++++++++++++ .../mlx-community--DeepSeek-V3.1-4bit.toml | 2 + .../mlx-community--DeepSeek-V3.1-8bit.toml | 2 + .../mlx-community--DeepSeek-V3.2-4bit.toml | 2 + .../mlx-community--DeepSeek-V3.2-8bit.toml | 2 + .../mlx-community--GLM-4.5-Air-8bit.toml | 2 + .../mlx-community--GLM-4.5-Air-bf16.toml | 2 + .../mlx-community--GLM-4.7-4bit.toml | 2 + .../mlx-community--GLM-4.7-6bit.toml | 2 + .../mlx-community--GLM-4.7-8bit-gs32.toml | 2 + .../mlx-community--GLM-4.7-Flash-4bit.toml | 2 + .../mlx-community--GLM-4.7-Flash-5bit.toml | 2 + .../mlx-community--GLM-4.7-Flash-6bit.toml | 2 + .../mlx-community--GLM-4.7-Flash-8bit.toml | 2 + .../mlx-community--GLM-5-8bit.toml | 2 + .../mlx-community--GLM-5-MXFP4-Q8.toml | 2 + .../mlx-community--GLM-5-bf16.toml | 2 + .../mlx-community--Kimi-K2-Instruct-4bit.toml | 2 + .../mlx-community--Kimi-K2-Thinking.toml | 2 + .../mlx-community--Kimi-K2.5.toml | 2 + ...ama-3.1-Nemotron-70B-Instruct-HF-4bit.toml | 2 + ...ama-3.1-Nemotron-70B-Instruct-HF-8bit.toml | 2 + ...ama-3.1-Nemotron-70B-Instruct-HF-bf16.toml | 2 + ...-Llama-3.1-Nemotron-Nano-4B-v1.1-4bit.toml | 2 + ...-Llama-3.1-Nemotron-Nano-4B-v1.1-8bit.toml | 2 + ...-Llama-3.1-Nemotron-Nano-4B-v1.1-bf16.toml | 2 + ...community--Llama-3.2-1B-Instruct-4bit.toml | 2 + ...community--Llama-3.2-3B-Instruct-4bit.toml | 2 + ...community--Llama-3.2-3B-Instruct-8bit.toml | 2 + ...ommunity--Llama-3.3-70B-Instruct-4bit.toml | 2 + ...ommunity--Llama-3.3-70B-Instruct-8bit.toml | 2 + ...ity--Meta-Llama-3.1-70B-Instruct-4bit.toml | 2 + ...nity--Meta-Llama-3.1-8B-Instruct-4bit.toml | 2 + ...nity--Meta-Llama-3.1-8B-Instruct-8bit.toml | 2 + ...nity--Meta-Llama-3.1-8B-Instruct-bf16.toml | 2 + .../mlx-community--MiniMax-M2.1-3bit.toml | 2 + .../mlx-community--MiniMax-M2.1-8bit.toml | 2 + .../mlx-community--MiniMax-M2.5-4bit.toml | 2 + .../mlx-community--MiniMax-M2.5-6bit.toml | 2 + .../mlx-community--MiniMax-M2.5-8bit.toml | 2 + ...IDIA-Nemotron-3-Nano-30B-A3B-MLX-4Bit.toml | 2 + ...IDIA-Nemotron-3-Nano-30B-A3B-MLX-5Bit.toml | 2 + ...IDIA-Nemotron-3-Nano-30B-A3B-MLX-6Bit.toml | 2 + ...IDIA-Nemotron-3-Nano-30B-A3B-MLX-8Bit.toml | 2 + ...IDIA-Nemotron-3-Nano-30B-A3B-MLX-BF16.toml | 2 + ...DIA-Nemotron-3-Nano-30B-A3B-MLX-MXFP4.toml | 2 + ...-NVIDIA-Nemotron-3-Nano-30B-A3B-NVFP4.toml | 2 + ...ity--NVIDIA-Nemotron-Nano-9B-v2-4bits.toml | 2 + ...nity--NVIDIA-Nemotron-Nano-9B-v2-6bit.toml | 2 + .../mlx-community--Qwen3-0.6B-4bit.toml | 2 + .../mlx-community--Qwen3-0.6B-8bit.toml | 2 + ...y--Qwen3-235B-A22B-Instruct-2507-4bit.toml | 2 + ...y--Qwen3-235B-A22B-Instruct-2507-8bit.toml | 2 + .../mlx-community--Qwen3-30B-A3B-4bit.toml | 2 + .../mlx-community--Qwen3-30B-A3B-8bit.toml | 2 + ...--Qwen3-Coder-480B-A35B-Instruct-4bit.toml | 2 + ...--Qwen3-Coder-480B-A35B-Instruct-8bit.toml | 2 + .../mlx-community--Qwen3-Coder-Next-4bit.toml | 2 + .../mlx-community--Qwen3-Coder-Next-5bit.toml | 2 + .../mlx-community--Qwen3-Coder-Next-6bit.toml | 2 + .../mlx-community--Qwen3-Coder-Next-8bit.toml | 2 + .../mlx-community--Qwen3-Coder-Next-bf16.toml | 2 + ...ity--Qwen3-Next-80B-A3B-Instruct-4bit.toml | 2 + ...ity--Qwen3-Next-80B-A3B-Instruct-8bit.toml | 2 + ...ity--Qwen3-Next-80B-A3B-Thinking-4bit.toml | 2 + ...ity--Qwen3-Next-80B-A3B-Thinking-8bit.toml | 2 + ...-community--Qwen3-VL-4B-Instruct-4bit.toml | 2 + ...mlx-community--Qwen3.5-122B-A10B-4bit.toml | 4 +- ...mlx-community--Qwen3.5-122B-A10B-6bit.toml | 4 +- ...mlx-community--Qwen3.5-122B-A10B-8bit.toml | 4 +- ...mlx-community--Qwen3.5-122B-A10B-bf16.toml | 4 +- .../mlx-community--Qwen3.5-27B-4bit.toml | 4 +- .../mlx-community--Qwen3.5-27B-8bit.toml | 4 +- .../mlx-community--Qwen3.5-2B-MLX-8bit.toml | 4 +- .../mlx-community--Qwen3.5-35B-A3B-4bit.toml | 4 +- .../mlx-community--Qwen3.5-35B-A3B-8bit.toml | 4 +- ...mlx-community--Qwen3.5-397B-A17B-4bit.toml | 4 +- ...mlx-community--Qwen3.5-397B-A17B-6bit.toml | 4 +- ...mlx-community--Qwen3.5-397B-A17B-8bit.toml | 4 +- .../mlx-community--Qwen3.5-9B-4bit.toml | 4 +- .../mlx-community--Qwen3.5-9B-8bit.toml | 4 +- .../mlx-community--Step-3.5-Flash-4bit.toml | 2 + .../mlx-community--Step-3.5-Flash-6bit.toml | 2 + .../mlx-community--Step-3.5-Flash-8Bit.toml | 2 + .../mlx-community--gpt-oss-120b-MXFP4-Q8.toml | 2 + .../mlx-community--gpt-oss-20b-MXFP4-Q8.toml | 2 + ...ommunity--llama-3.3-70b-instruct-fp16.toml | 2 + src/exo/api/adapters/responses.py | 278 +++++++-- src/exo/api/main.py | 1 + src/exo/api/types/openai_responses.py | 222 ++++++- src/exo/shared/models/model_cards.py | 4 + .../engines/mlx/generator/batch_generate.py | 2 + .../worker/engines/mlx/generator/generate.py | 2 + src/exo/worker/engines/mlx/utils_mlx.py | 74 ++- src/exo/worker/engines/mlx/vision.py | 21 +- 98 files changed, 1394 insertions(+), 108 deletions(-) create mode 100644 dashboard/src/lib/components/IntegrationCard.svelte create mode 100644 dashboard/src/routes/integrations/+page.svelte diff --git a/dashboard/src/lib/components/HeaderNav.svelte b/dashboard/src/lib/components/HeaderNav.svelte index 16582a64..d7dab78d 100644 --- a/dashboard/src/lib/components/HeaderNav.svelte +++ b/dashboard/src/lib/components/HeaderNav.svelte @@ -1,21 +1,38 @@ + +
+
+
+

{title}

+

{subtitle}

+
+ +
+ {#if description} +

{description}

+ {/if} +
+
{config}
+
+
diff --git a/dashboard/src/lib/components/index.ts b/dashboard/src/lib/components/index.ts index 7efe0f87..07192376 100644 --- a/dashboard/src/lib/components/index.ts +++ b/dashboard/src/lib/components/index.ts @@ -13,3 +13,4 @@ export { default as ModelFilterPopover } from "./ModelFilterPopover.svelte"; export { default as ModelPickerGroup } from "./ModelPickerGroup.svelte"; export { default as ModelPickerModal } from "./ModelPickerModal.svelte"; export { default as ChatModelSelector } from "./ChatModelSelector.svelte"; +export { default as IntegrationCard } from "./IntegrationCard.svelte"; diff --git a/dashboard/src/routes/integrations/+page.svelte b/dashboard/src/routes/integrations/+page.svelte new file mode 100644 index 00000000..924cfdf7 --- /dev/null +++ b/dashboard/src/routes/integrations/+page.svelte @@ -0,0 +1,577 @@ + + +
+ + +
+
+

+ Integrations +

+

+ Connect external tools to your exo cluster. +

+
+ + +
+ API Endpoint + {apiUrl} + {#if runningModels.length > 0} +
+ Running model{runningModels.length > 1 ? "s" : ""}: +
    + {#each runningModels as model} +
  • {model}
  • + {/each} +
+
+ {:else} +

+ No models currently running +

+ {/if} +
+ + +
+
+
+ OpenAI-compatible + {apiUrl}/v1 +
+
+ Claude-compatible + {apiUrl} +
+
+ Ollama-compatible + {apiUrl}/ollama +
+
+
+ + +
+ {#each tabs as tab} + + {/each} +
+ + +
+ {#if activeTab === "Claude Code"} + {#if runningModels.length > 1} +
+ {#each [{ label: "Opus", bind: () => opusModel, set: (v: string) => (opusModel = v) }, { label: "Sonnet", bind: () => sonnetModel, set: (v: string) => (sonnetModel = v) }, { label: "Haiku", bind: () => haikuModel, set: (v: string) => (haikuModel = v) }] as tier} +
+ {tier.label} + +
+ {/each} +
+ {/if} + + + {:else if activeTab === "OpenCode"} + + {:else if activeTab === "Codex"} +
+ {#if runningModels.length > 1} +
+ Model + +
+ {/if} +
+ MCP Filesystem Path + +
+
+ + + {:else if activeTab === "OpenClaw"} + {#if runningModels.length > 1} +
+ Model + +
+ {/if} + + + {:else if activeTab === "Open WebUI"} + + 0 ? runningModels.join(", ") : "no models running"}`} + config={"open http://localhost:3000"} + language="bash" + /> + + {:else if activeTab === "n8n"} + + + + + {:else if activeTab === "Firefox"} + + {/if} +
+
+
diff --git a/resources/inference_model_cards/mlx-community--DeepSeek-V3.1-4bit.toml b/resources/inference_model_cards/mlx-community--DeepSeek-V3.1-4bit.toml index 8c415095..01166482 100644 --- a/resources/inference_model_cards/mlx-community--DeepSeek-V3.1-4bit.toml +++ b/resources/inference_model_cards/mlx-community--DeepSeek-V3.1-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "DeepSeek V3.1" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 131072 + [storage_size] in_bytes = 405874409472 diff --git a/resources/inference_model_cards/mlx-community--DeepSeek-V3.1-8bit.toml b/resources/inference_model_cards/mlx-community--DeepSeek-V3.1-8bit.toml index a1889395..62313d3a 100644 --- a/resources/inference_model_cards/mlx-community--DeepSeek-V3.1-8bit.toml +++ b/resources/inference_model_cards/mlx-community--DeepSeek-V3.1-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "DeepSeek V3.1" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 131072 + [storage_size] in_bytes = 765577920512 diff --git a/resources/inference_model_cards/mlx-community--DeepSeek-V3.2-4bit.toml b/resources/inference_model_cards/mlx-community--DeepSeek-V3.2-4bit.toml index 0ca9bb22..5288181e 100644 --- a/resources/inference_model_cards/mlx-community--DeepSeek-V3.2-4bit.toml +++ b/resources/inference_model_cards/mlx-community--DeepSeek-V3.2-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "DeepSeek V3.2" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 131072 + [storage_size] in_bytes = 378086226621 diff --git a/resources/inference_model_cards/mlx-community--DeepSeek-V3.2-8bit.toml b/resources/inference_model_cards/mlx-community--DeepSeek-V3.2-8bit.toml index a6d9d628..87f81738 100644 --- a/resources/inference_model_cards/mlx-community--DeepSeek-V3.2-8bit.toml +++ b/resources/inference_model_cards/mlx-community--DeepSeek-V3.2-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "DeepSeek V3.2" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 131072 + [storage_size] in_bytes = 755957120916 diff --git a/resources/inference_model_cards/mlx-community--GLM-4.5-Air-8bit.toml b/resources/inference_model_cards/mlx-community--GLM-4.5-Air-8bit.toml index efa2c1f6..644fe425 100644 --- a/resources/inference_model_cards/mlx-community--GLM-4.5-Air-8bit.toml +++ b/resources/inference_model_cards/mlx-community--GLM-4.5-Air-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "GLM 4.5 Air" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 131072 + [storage_size] in_bytes = 122406567936 diff --git a/resources/inference_model_cards/mlx-community--GLM-4.5-Air-bf16.toml b/resources/inference_model_cards/mlx-community--GLM-4.5-Air-bf16.toml index 42727eed..a7b5c37a 100644 --- a/resources/inference_model_cards/mlx-community--GLM-4.5-Air-bf16.toml +++ b/resources/inference_model_cards/mlx-community--GLM-4.5-Air-bf16.toml @@ -9,5 +9,7 @@ quantization = "bf16" base_model = "GLM 4.5 Air" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 131072 + [storage_size] in_bytes = 229780750336 diff --git a/resources/inference_model_cards/mlx-community--GLM-4.7-4bit.toml b/resources/inference_model_cards/mlx-community--GLM-4.7-4bit.toml index 22fba6a9..c8b32a38 100644 --- a/resources/inference_model_cards/mlx-community--GLM-4.7-4bit.toml +++ b/resources/inference_model_cards/mlx-community--GLM-4.7-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "GLM 4.7" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 202752 + [storage_size] in_bytes = 198556925568 diff --git a/resources/inference_model_cards/mlx-community--GLM-4.7-6bit.toml b/resources/inference_model_cards/mlx-community--GLM-4.7-6bit.toml index b83c34e5..7eb301e5 100644 --- a/resources/inference_model_cards/mlx-community--GLM-4.7-6bit.toml +++ b/resources/inference_model_cards/mlx-community--GLM-4.7-6bit.toml @@ -9,5 +9,7 @@ quantization = "6bit" base_model = "GLM 4.7" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 202752 + [storage_size] in_bytes = 286737579648 diff --git a/resources/inference_model_cards/mlx-community--GLM-4.7-8bit-gs32.toml b/resources/inference_model_cards/mlx-community--GLM-4.7-8bit-gs32.toml index 3f6b2391..91365de8 100644 --- a/resources/inference_model_cards/mlx-community--GLM-4.7-8bit-gs32.toml +++ b/resources/inference_model_cards/mlx-community--GLM-4.7-8bit-gs32.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "GLM 4.7" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 202752 + [storage_size] in_bytes = 396963397248 diff --git a/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-4bit.toml b/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-4bit.toml index ca183ded..d0be6d82 100644 --- a/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-4bit.toml +++ b/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "GLM 4.7 Flash" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 202752 + [storage_size] in_bytes = 19327352832 diff --git a/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-5bit.toml b/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-5bit.toml index 3b0c06c9..9c7136db 100644 --- a/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-5bit.toml +++ b/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-5bit.toml @@ -9,5 +9,7 @@ quantization = "5bit" base_model = "GLM 4.7 Flash" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 202752 + [storage_size] in_bytes = 22548578304 diff --git a/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-6bit.toml b/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-6bit.toml index 8669298f..cf2ed455 100644 --- a/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-6bit.toml +++ b/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-6bit.toml @@ -9,5 +9,7 @@ quantization = "6bit" base_model = "GLM 4.7 Flash" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 202752 + [storage_size] in_bytes = 26843545600 diff --git a/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-8bit.toml b/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-8bit.toml index 3ffcacb2..879b322c 100644 --- a/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-8bit.toml +++ b/resources/inference_model_cards/mlx-community--GLM-4.7-Flash-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "GLM 4.7 Flash" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 202752 + [storage_size] in_bytes = 34359738368 diff --git a/resources/inference_model_cards/mlx-community--GLM-5-8bit.toml b/resources/inference_model_cards/mlx-community--GLM-5-8bit.toml index 5affe179..37b0fb2a 100644 --- a/resources/inference_model_cards/mlx-community--GLM-5-8bit.toml +++ b/resources/inference_model_cards/mlx-community--GLM-5-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "GLM-5" capabilities = ["text", "thinking"] +context_length = 202752 + [storage_size] in_bytes = 790517400864 diff --git a/resources/inference_model_cards/mlx-community--GLM-5-MXFP4-Q8.toml b/resources/inference_model_cards/mlx-community--GLM-5-MXFP4-Q8.toml index 8e942ed3..2874e4e6 100644 --- a/resources/inference_model_cards/mlx-community--GLM-5-MXFP4-Q8.toml +++ b/resources/inference_model_cards/mlx-community--GLM-5-MXFP4-Q8.toml @@ -9,5 +9,7 @@ quantization = "MXFP4-Q8" base_model = "GLM-5" capabilities = ["text", "thinking"] +context_length = 202752 + [storage_size] in_bytes = 405478939008 diff --git a/resources/inference_model_cards/mlx-community--GLM-5-bf16.toml b/resources/inference_model_cards/mlx-community--GLM-5-bf16.toml index 2803710e..1086d86a 100644 --- a/resources/inference_model_cards/mlx-community--GLM-5-bf16.toml +++ b/resources/inference_model_cards/mlx-community--GLM-5-bf16.toml @@ -9,5 +9,7 @@ quantization = "bf16" base_model = "GLM-5" capabilities = ["text", "thinking"] +context_length = 202752 + [storage_size] in_bytes = 1487822475264 diff --git a/resources/inference_model_cards/mlx-community--Kimi-K2-Instruct-4bit.toml b/resources/inference_model_cards/mlx-community--Kimi-K2-Instruct-4bit.toml index da82c4d8..878aa2aa 100644 --- a/resources/inference_model_cards/mlx-community--Kimi-K2-Instruct-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Kimi-K2-Instruct-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Kimi K2" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 620622774272 diff --git a/resources/inference_model_cards/mlx-community--Kimi-K2-Thinking.toml b/resources/inference_model_cards/mlx-community--Kimi-K2-Thinking.toml index d088b615..37f4befc 100644 --- a/resources/inference_model_cards/mlx-community--Kimi-K2-Thinking.toml +++ b/resources/inference_model_cards/mlx-community--Kimi-K2-Thinking.toml @@ -9,5 +9,7 @@ quantization = "" base_model = "Kimi K2" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 262144 + [storage_size] in_bytes = 706522120192 diff --git a/resources/inference_model_cards/mlx-community--Kimi-K2.5.toml b/resources/inference_model_cards/mlx-community--Kimi-K2.5.toml index a2eea6c3..efe7d4bb 100644 --- a/resources/inference_model_cards/mlx-community--Kimi-K2.5.toml +++ b/resources/inference_model_cards/mlx-community--Kimi-K2.5.toml @@ -9,6 +9,8 @@ quantization = "" base_model = "Kimi K2.5" capabilities = ["text", "thinking", "thinking_toggle", "vision"] +context_length = 262144 + [storage_size] in_bytes = 662498705408 diff --git a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-4bit.toml b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-4bit.toml index 2aacb04e..d98cabdd 100644 --- a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-4bit.toml @@ -8,5 +8,7 @@ quantization = "4bit" base_model = "NVIDIA Llama-3.1-Nemotron-70B-Instruct" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 39688355840 diff --git a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-8bit.toml b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-8bit.toml index f7c34f8e..4f4297ab 100644 --- a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-8bit.toml @@ -8,5 +8,7 @@ quantization = "8bit" base_model = "NVIDIA Llama-3.1-Nemotron-70B-Instruct" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 74964549632 diff --git a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-bf16.toml b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-bf16.toml index f513934b..4ef63c17 100644 --- a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-bf16.toml +++ b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-70B-Instruct-HF-bf16.toml @@ -8,5 +8,7 @@ quantization = "bf16" base_model = "NVIDIA Llama-3.1-Nemotron-70B-Instruct" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 141107412992 diff --git a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-4bit.toml b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-4bit.toml index 12707721..687c5664 100644 --- a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-4bit.toml @@ -8,5 +8,7 @@ quantization = "4bit" base_model = "NVIDIA Llama-3.1-Nemotron-Nano-4B-v1.1" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 2538706944 diff --git a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-8bit.toml b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-8bit.toml index b4baebc6..dae6fd93 100644 --- a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-8bit.toml @@ -8,5 +8,7 @@ quantization = "8bit" base_model = "NVIDIA Llama-3.1-Nemotron-Nano-4B-v1.1" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 4794980352 diff --git a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-bf16.toml b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-bf16.toml index 2258b856..0e261646 100644 --- a/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-bf16.toml +++ b/resources/inference_model_cards/mlx-community--Llama-3.1-Nemotron-Nano-4B-v1.1-bf16.toml @@ -8,5 +8,7 @@ quantization = "bf16" base_model = "NVIDIA Llama-3.1-Nemotron-Nano-4B-v1.1" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 9025492992 diff --git a/resources/inference_model_cards/mlx-community--Llama-3.2-1B-Instruct-4bit.toml b/resources/inference_model_cards/mlx-community--Llama-3.2-1B-Instruct-4bit.toml index 888b9f97..fa30edc3 100644 --- a/resources/inference_model_cards/mlx-community--Llama-3.2-1B-Instruct-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Llama-3.2-1B-Instruct-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Llama 3.2 1B" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 729808896 diff --git a/resources/inference_model_cards/mlx-community--Llama-3.2-3B-Instruct-4bit.toml b/resources/inference_model_cards/mlx-community--Llama-3.2-3B-Instruct-4bit.toml index 60486e64..6255db7b 100644 --- a/resources/inference_model_cards/mlx-community--Llama-3.2-3B-Instruct-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Llama-3.2-3B-Instruct-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Llama 3.2 3B" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 1863319552 diff --git a/resources/inference_model_cards/mlx-community--Llama-3.2-3B-Instruct-8bit.toml b/resources/inference_model_cards/mlx-community--Llama-3.2-3B-Instruct-8bit.toml index d252a2e5..e2de35ec 100644 --- a/resources/inference_model_cards/mlx-community--Llama-3.2-3B-Instruct-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Llama-3.2-3B-Instruct-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "Llama 3.2 3B" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 3501195264 diff --git a/resources/inference_model_cards/mlx-community--Llama-3.3-70B-Instruct-4bit.toml b/resources/inference_model_cards/mlx-community--Llama-3.3-70B-Instruct-4bit.toml index 03f9c12b..ef81e828 100644 --- a/resources/inference_model_cards/mlx-community--Llama-3.3-70B-Instruct-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Llama-3.3-70B-Instruct-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Llama 3.3 70B" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 40652242944 diff --git a/resources/inference_model_cards/mlx-community--Llama-3.3-70B-Instruct-8bit.toml b/resources/inference_model_cards/mlx-community--Llama-3.3-70B-Instruct-8bit.toml index ef0254a8..fb83f3d0 100644 --- a/resources/inference_model_cards/mlx-community--Llama-3.3-70B-Instruct-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Llama-3.3-70B-Instruct-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "Llama 3.3 70B" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 76799803392 diff --git a/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-70B-Instruct-4bit.toml b/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-70B-Instruct-4bit.toml index d4c57ae1..89313087 100644 --- a/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-70B-Instruct-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-70B-Instruct-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Llama 3.1 70B" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 40652242944 diff --git a/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-4bit.toml b/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-4bit.toml index 816564a0..a9ab123b 100644 --- a/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Llama 3.1 8B" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 4637851648 diff --git a/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-8bit.toml b/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-8bit.toml index ff82803a..84cdbaf1 100644 --- a/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "Llama 3.1 8B" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 8954839040 diff --git a/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-bf16.toml b/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-bf16.toml index db19a097..f2121d64 100644 --- a/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-bf16.toml +++ b/resources/inference_model_cards/mlx-community--Meta-Llama-3.1-8B-Instruct-bf16.toml @@ -9,5 +9,7 @@ quantization = "bf16" base_model = "Llama 3.1 8B" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 16882073600 diff --git a/resources/inference_model_cards/mlx-community--MiniMax-M2.1-3bit.toml b/resources/inference_model_cards/mlx-community--MiniMax-M2.1-3bit.toml index ec1e4f50..0b22f011 100644 --- a/resources/inference_model_cards/mlx-community--MiniMax-M2.1-3bit.toml +++ b/resources/inference_model_cards/mlx-community--MiniMax-M2.1-3bit.toml @@ -9,5 +9,7 @@ quantization = "3bit" base_model = "MiniMax M2.1" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 196608 + [storage_size] in_bytes = 100086644736 diff --git a/resources/inference_model_cards/mlx-community--MiniMax-M2.1-8bit.toml b/resources/inference_model_cards/mlx-community--MiniMax-M2.1-8bit.toml index c3bb8177..32e5bc3f 100644 --- a/resources/inference_model_cards/mlx-community--MiniMax-M2.1-8bit.toml +++ b/resources/inference_model_cards/mlx-community--MiniMax-M2.1-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "MiniMax M2.1" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 196608 + [storage_size] in_bytes = 242986745856 diff --git a/resources/inference_model_cards/mlx-community--MiniMax-M2.5-4bit.toml b/resources/inference_model_cards/mlx-community--MiniMax-M2.5-4bit.toml index 963b3b9b..c6418512 100644 --- a/resources/inference_model_cards/mlx-community--MiniMax-M2.5-4bit.toml +++ b/resources/inference_model_cards/mlx-community--MiniMax-M2.5-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "MiniMax M2.5" capabilities = ["text", "thinking"] +context_length = 196608 + [storage_size] in_bytes = 128666664960 diff --git a/resources/inference_model_cards/mlx-community--MiniMax-M2.5-6bit.toml b/resources/inference_model_cards/mlx-community--MiniMax-M2.5-6bit.toml index af329569..9c366e6e 100644 --- a/resources/inference_model_cards/mlx-community--MiniMax-M2.5-6bit.toml +++ b/resources/inference_model_cards/mlx-community--MiniMax-M2.5-6bit.toml @@ -9,5 +9,7 @@ quantization = "6bit" base_model = "MiniMax M2.5" capabilities = ["text", "thinking"] +context_length = 196608 + [storage_size] in_bytes = 185826705408 diff --git a/resources/inference_model_cards/mlx-community--MiniMax-M2.5-8bit.toml b/resources/inference_model_cards/mlx-community--MiniMax-M2.5-8bit.toml index 2a39701d..c6946fa4 100644 --- a/resources/inference_model_cards/mlx-community--MiniMax-M2.5-8bit.toml +++ b/resources/inference_model_cards/mlx-community--MiniMax-M2.5-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "MiniMax M2.5" capabilities = ["text", "thinking"] +context_length = 196608 + [storage_size] in_bytes = 242986745856 diff --git a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-4Bit.toml b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-4Bit.toml index f40798ea..7b79a205 100644 --- a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-4Bit.toml +++ b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-4Bit.toml @@ -8,5 +8,7 @@ quantization = "4bit" base_model = "NVIDIA Nemotron-3-Nano-30B-A3B" capabilities = ["text"] +context_length = 262144 + [storage_size] in_bytes = 17775342336 diff --git a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-5Bit.toml b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-5Bit.toml index 15761184..8a4c7384 100644 --- a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-5Bit.toml +++ b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-5Bit.toml @@ -8,5 +8,7 @@ quantization = "5bit" base_model = "NVIDIA Nemotron-3-Nano-30B-A3B" capabilities = ["text"] +context_length = 262144 + [storage_size] in_bytes = 21721476864 diff --git a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-6Bit.toml b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-6Bit.toml index 238d4fe3..96b7a7fb 100644 --- a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-6Bit.toml +++ b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-6Bit.toml @@ -8,5 +8,7 @@ quantization = "6bit" base_model = "NVIDIA Nemotron-3-Nano-30B-A3B" capabilities = ["text"] +context_length = 262144 + [storage_size] in_bytes = 25667611392 diff --git a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-8Bit.toml b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-8Bit.toml index 7317de54..1c95fa90 100644 --- a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-8Bit.toml +++ b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-8Bit.toml @@ -8,5 +8,7 @@ quantization = "8bit" base_model = "NVIDIA Nemotron-3-Nano-30B-A3B" capabilities = ["text"] +context_length = 262144 + [storage_size] in_bytes = 33559880448 diff --git a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-BF16.toml b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-BF16.toml index fd8886af..5364e5bc 100644 --- a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-BF16.toml +++ b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-BF16.toml @@ -8,5 +8,7 @@ quantization = "bf16" base_model = "NVIDIA Nemotron-3-Nano-30B-A3B" capabilities = ["text"] +context_length = 262144 + [storage_size] in_bytes = 63155889408 diff --git a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-MXFP4.toml b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-MXFP4.toml index ec402a22..1c7137da 100644 --- a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-MXFP4.toml +++ b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-MLX-MXFP4.toml @@ -8,5 +8,7 @@ quantization = "4bit" base_model = "NVIDIA Nemotron-3-Nano-30B-A3B" capabilities = ["text"] +context_length = 262144 + [storage_size] in_bytes = 16788808704 diff --git a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-NVFP4.toml b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-NVFP4.toml index d9b86095..13aae100 100644 --- a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-NVFP4.toml +++ b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-3-Nano-30B-A3B-NVFP4.toml @@ -8,5 +8,7 @@ quantization = "4bit" base_model = "NVIDIA Nemotron-3-Nano-30B-A3B" capabilities = ["text"] +context_length = 262144 + [storage_size] in_bytes = 19323906944 diff --git a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-Nano-9B-v2-4bits.toml b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-Nano-9B-v2-4bits.toml index 8084787e..649fecd9 100644 --- a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-Nano-9B-v2-4bits.toml +++ b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-Nano-9B-v2-4bits.toml @@ -8,5 +8,7 @@ quantization = "4bit" base_model = "NVIDIA Nemotron-Nano-9B-v2" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 5002791936 diff --git a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-Nano-9B-v2-6bit.toml b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-Nano-9B-v2-6bit.toml index 4f09bde3..e5c6422b 100644 --- a/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-Nano-9B-v2-6bit.toml +++ b/resources/inference_model_cards/mlx-community--NVIDIA-Nemotron-Nano-9B-v2-6bit.toml @@ -8,5 +8,7 @@ quantization = "6bit" base_model = "NVIDIA Nemotron-Nano-9B-v2" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 7224298496 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-0.6B-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-0.6B-4bit.toml index 5b4bd368..f99033fc 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-0.6B-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-0.6B-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Qwen3 0.6B" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 32768 + [storage_size] in_bytes = 342884352 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-0.6B-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-0.6B-8bit.toml index 0dad33c0..8d7e7643 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-0.6B-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-0.6B-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "Qwen3 0.6B" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 32768 + [storage_size] in_bytes = 698351616 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-235B-A22B-Instruct-2507-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-235B-A22B-Instruct-2507-4bit.toml index 4a4fb10f..6e2709f5 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-235B-A22B-Instruct-2507-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-235B-A22B-Instruct-2507-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Qwen3 235B" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 262144 + [storage_size] in_bytes = 141733920768 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-235B-A22B-Instruct-2507-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-235B-A22B-Instruct-2507-8bit.toml index ed70dca4..0e41f4ed 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-235B-A22B-Instruct-2507-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-235B-A22B-Instruct-2507-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "Qwen3 235B" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 262144 + [storage_size] in_bytes = 268435456000 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-30B-A3B-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-30B-A3B-4bit.toml index c0f7b577..4e736c14 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-30B-A3B-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-30B-A3B-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Qwen3 30B" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 32768 + [storage_size] in_bytes = 17612931072 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-30B-A3B-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-30B-A3B-8bit.toml index 4018ec2d..15308a84 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-30B-A3B-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-30B-A3B-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "Qwen3 30B" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 32768 + [storage_size] in_bytes = 33279705088 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-Coder-480B-A35B-Instruct-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-Coder-480B-A35B-Instruct-4bit.toml index e4838f9c..95010af8 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-Coder-480B-A35B-Instruct-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-Coder-480B-A35B-Instruct-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Qwen3 Coder 480B" capabilities = ["text", "code"] +context_length = 262144 + [storage_size] in_bytes = 289910292480 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-Coder-480B-A35B-Instruct-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-Coder-480B-A35B-Instruct-8bit.toml index 44558b78..963fb205 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-Coder-480B-A35B-Instruct-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-Coder-480B-A35B-Instruct-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "Qwen3 Coder 480B" capabilities = ["text", "code"] +context_length = 262144 + [storage_size] in_bytes = 579820584960 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-4bit.toml index a81e0059..e28c1d95 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Qwen3 Coder Next" capabilities = ["text", "code"] +context_length = 262144 + [storage_size] in_bytes = 45644286500 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-5bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-5bit.toml index 535b62eb..58c63f78 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-5bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-5bit.toml @@ -9,5 +9,7 @@ quantization = "5bit" base_model = "Qwen3 Coder Next" capabilities = ["text", "code"] +context_length = 262144 + [storage_size] in_bytes = 57657697020 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-6bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-6bit.toml index 4ad7289d..17f921e5 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-6bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-6bit.toml @@ -9,5 +9,7 @@ quantization = "6bit" base_model = "Qwen3 Coder Next" capabilities = ["text", "code"] +context_length = 262144 + [storage_size] in_bytes = 68899327465 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-8bit.toml index 51f13a63..934894ac 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "Qwen3 Coder Next" capabilities = ["text", "code"] +context_length = 262144 + [storage_size] in_bytes = 89357758772 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-bf16.toml b/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-bf16.toml index 76d77693..fd135bb0 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-bf16.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-Coder-Next-bf16.toml @@ -9,5 +9,7 @@ quantization = "bf16" base_model = "Qwen3 Coder Next" capabilities = ["text", "code"] +context_length = 262144 + [storage_size] in_bytes = 157548627945 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Instruct-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Instruct-4bit.toml index d9eb5845..7a331b46 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Instruct-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Instruct-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Qwen3 Next 80B" capabilities = ["text"] +context_length = 262144 + [storage_size] in_bytes = 46976204800 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Instruct-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Instruct-8bit.toml index 09352d3f..a54f01de 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Instruct-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Instruct-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "Qwen3 Next 80B" capabilities = ["text"] +context_length = 262144 + [storage_size] in_bytes = 88814387200 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Thinking-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Thinking-4bit.toml index 12f341fb..d126f727 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Thinking-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Thinking-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Qwen3 Next 80B" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 262144 + [storage_size] in_bytes = 47080074240 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Thinking-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Thinking-8bit.toml index 7a52dbf7..b008b130 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Thinking-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-Next-80B-A3B-Thinking-8bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "Qwen3 Next 80B" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 262144 + [storage_size] in_bytes = 88814387200 diff --git a/resources/inference_model_cards/mlx-community--Qwen3-VL-4B-Instruct-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3-VL-4B-Instruct-4bit.toml index b1cd18f6..6d34735f 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3-VL-4B-Instruct-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3-VL-4B-Instruct-4bit.toml @@ -8,5 +8,7 @@ quantization = "4bit" base_model = "Qwen3-VL 4B" capabilities = ["text", "thinking", "vision"] +context_length = 262144 + [storage_size] in_bytes = 3340000000 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-4bit.toml index 452b0a44..100ab997 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-4bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "4bit" base_model = "Qwen3.5 122B A10B" -capabilities = ["text", "thinking", "thinking_toggle"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 69593314272 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-6bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-6bit.toml index 7c01c831..99177f48 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-6bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-6bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "6bit" base_model = "Qwen3.5 122B A10B" -capabilities = ["text", "thinking", "thinking_toggle"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 100120675296 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-8bit.toml index 12c6a460..cff7cf62 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-8bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "8bit" base_model = "Qwen3.5 122B A10B" -capabilities = ["text", "thinking", "thinking_toggle"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 130648036320 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-bf16.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-bf16.toml index a4b22916..2299c8e7 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-bf16.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-122B-A10B-bf16.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "bf16" base_model = "Qwen3.5 122B A10B" -capabilities = ["text", "thinking", "thinking_toggle"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 245125640160 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-27B-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-27B-4bit.toml index ee42738f..8c8a4f11 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-27B-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-27B-4bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "4bit" base_model = "Qwen3.5 27B" -capabilities = ["text", "thinking"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 16054266848 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-27B-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-27B-8bit.toml index 42b1184c..3c7dc6eb 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-27B-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-27B-8bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "8bit" base_model = "Qwen3.5 27B" -capabilities = ["text", "thinking"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 29500943328 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-2B-MLX-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-2B-MLX-8bit.toml index b1821192..a62d4495 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-2B-MLX-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-2B-MLX-8bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "8bit" base_model = "Qwen3.5 2B" -capabilities = ["text", "thinking"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 2662787264 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-35B-A3B-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-35B-A3B-4bit.toml index 1c0a6fe9..dfb5e244 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-35B-A3B-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-35B-A3B-4bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "4bit" base_model = "Qwen3.5 35B A3B" -capabilities = ["text", "thinking", "thinking_toggle"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 20391405152 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-35B-A3B-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-35B-A3B-8bit.toml index 64b7a61e..24881e04 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-35B-A3B-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-35B-A3B-8bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "8bit" base_model = "Qwen3.5 35B A3B" -capabilities = ["text", "thinking", "thinking_toggle"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 37721130592 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-4bit.toml index 10af0e43..7823e87b 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-4bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "4bit" base_model = "Qwen3.5 397B A17B" -capabilities = ["text", "thinking", "thinking_toggle"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 223860768352 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-6bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-6bit.toml index b8427aa1..8df64cad 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-6bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-6bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "6bit" base_model = "Qwen3.5 397B A17B" -capabilities = ["text", "thinking", "thinking_toggle"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 322946674272 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-8bit.toml index 73fdbcd3..4aa63400 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-397B-A17B-8bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "8bit" base_model = "Qwen3.5 397B A17B" -capabilities = ["text", "thinking", "thinking_toggle"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 422032580192 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-9B-4bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-9B-4bit.toml index 67a4970f..c8bb95c7 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-9B-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-9B-4bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "4bit" base_model = "Qwen3.5 9B" -capabilities = ["text", "thinking"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 5950062560 diff --git a/resources/inference_model_cards/mlx-community--Qwen3.5-9B-8bit.toml b/resources/inference_model_cards/mlx-community--Qwen3.5-9B-8bit.toml index 3dcf5b0d..6b1dfede 100644 --- a/resources/inference_model_cards/mlx-community--Qwen3.5-9B-8bit.toml +++ b/resources/inference_model_cards/mlx-community--Qwen3.5-9B-8bit.toml @@ -7,7 +7,9 @@ tasks = ["TextGeneration"] family = "qwen" quantization = "8bit" base_model = "Qwen3.5 9B" -capabilities = ["text", "thinking"] +capabilities = ["text", "thinking", "thinking_toggle", "vision"] + +context_length = 262144 [storage_size] in_bytes = 10426433504 diff --git a/resources/inference_model_cards/mlx-community--Step-3.5-Flash-4bit.toml b/resources/inference_model_cards/mlx-community--Step-3.5-Flash-4bit.toml index 9dd73125..d2971641 100644 --- a/resources/inference_model_cards/mlx-community--Step-3.5-Flash-4bit.toml +++ b/resources/inference_model_cards/mlx-community--Step-3.5-Flash-4bit.toml @@ -9,5 +9,7 @@ quantization = "4bit" base_model = "Step 3.5 Flash" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 262144 + [storage_size] in_bytes = 114572190076 diff --git a/resources/inference_model_cards/mlx-community--Step-3.5-Flash-6bit.toml b/resources/inference_model_cards/mlx-community--Step-3.5-Flash-6bit.toml index f910f25f..4adc3bb4 100644 --- a/resources/inference_model_cards/mlx-community--Step-3.5-Flash-6bit.toml +++ b/resources/inference_model_cards/mlx-community--Step-3.5-Flash-6bit.toml @@ -9,5 +9,7 @@ quantization = "6bit" base_model = "Step 3.5 Flash" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 262144 + [storage_size] in_bytes = 159039627774 diff --git a/resources/inference_model_cards/mlx-community--Step-3.5-Flash-8Bit.toml b/resources/inference_model_cards/mlx-community--Step-3.5-Flash-8Bit.toml index eb4d635c..1306637c 100644 --- a/resources/inference_model_cards/mlx-community--Step-3.5-Flash-8Bit.toml +++ b/resources/inference_model_cards/mlx-community--Step-3.5-Flash-8Bit.toml @@ -9,5 +9,7 @@ quantization = "8bit" base_model = "Step 3.5 Flash" capabilities = ["text", "thinking", "thinking_toggle"] +context_length = 262144 + [storage_size] in_bytes = 209082699847 diff --git a/resources/inference_model_cards/mlx-community--gpt-oss-120b-MXFP4-Q8.toml b/resources/inference_model_cards/mlx-community--gpt-oss-120b-MXFP4-Q8.toml index 900c18f5..02e8b755 100644 --- a/resources/inference_model_cards/mlx-community--gpt-oss-120b-MXFP4-Q8.toml +++ b/resources/inference_model_cards/mlx-community--gpt-oss-120b-MXFP4-Q8.toml @@ -9,5 +9,7 @@ quantization = "MXFP4-Q8" base_model = "GPT-OSS 120B" capabilities = ["text", "thinking"] +context_length = 131072 + [storage_size] in_bytes = 70652212224 diff --git a/resources/inference_model_cards/mlx-community--gpt-oss-20b-MXFP4-Q8.toml b/resources/inference_model_cards/mlx-community--gpt-oss-20b-MXFP4-Q8.toml index 98748fd1..a363bfab 100644 --- a/resources/inference_model_cards/mlx-community--gpt-oss-20b-MXFP4-Q8.toml +++ b/resources/inference_model_cards/mlx-community--gpt-oss-20b-MXFP4-Q8.toml @@ -9,5 +9,7 @@ quantization = "MXFP4-Q8" base_model = "GPT-OSS 20B" capabilities = ["text", "thinking"] +context_length = 131072 + [storage_size] in_bytes = 12025908224 diff --git a/resources/inference_model_cards/mlx-community--llama-3.3-70b-instruct-fp16.toml b/resources/inference_model_cards/mlx-community--llama-3.3-70b-instruct-fp16.toml index a46dbb88..194a88d7 100644 --- a/resources/inference_model_cards/mlx-community--llama-3.3-70b-instruct-fp16.toml +++ b/resources/inference_model_cards/mlx-community--llama-3.3-70b-instruct-fp16.toml @@ -9,5 +9,7 @@ quantization = "fp16" base_model = "Llama 3.3 70B" capabilities = ["text"] +context_length = 131072 + [storage_size] in_bytes = 144383672320 diff --git a/src/exo/api/adapters/responses.py b/src/exo/api/adapters/responses.py index 37b72558..2e8baf14 100644 --- a/src/exo/api/adapters/responses.py +++ b/src/exo/api/adapters/responses.py @@ -1,5 +1,6 @@ """OpenAI Responses API adapter for converting requests/responses.""" +import json from collections.abc import AsyncGenerator from itertools import count from typing import Any @@ -10,7 +11,26 @@ from exo.api.adapters.chat_completions import ( ) from exo.api.types import Usage from exo.api.types.openai_responses import ( + ApplyPatchCallInputItem, + ApplyPatchCallOutputInputItem, + CodeInterpreterCallInputItem, + CompactionInputItem, + ComputerCallInputItem, + ComputerCallOutputInputItem, + CustomToolCallInputItem, + CustomToolCallOutputInputItem, + FileSearchCallInputItem, FunctionCallInputItem, + FunctionCallOutputInputItem, + ImageGenerationCallInputItem, + ItemReferenceInputItem, + LocalShellCallInputItem, + LocalShellCallOutputInputItem, + McpApprovalRequestInputItem, + McpApprovalResponseInputItem, + McpCallInputItem, + McpListToolsInputItem, + ReasoningInputItem, ResponseCompletedEvent, ResponseContentPart, ResponseContentPartAddedEvent, @@ -39,7 +59,13 @@ from exo.api.types.openai_responses import ( ResponseTextDeltaEvent, ResponseTextDoneEvent, ResponseUsage, + ShellCallInputItem, + ShellCallOutputInputItem, + ToolSearchCallInputItem, + ToolSearchOutputInputItem, + WebSearchCallInputItem, ) +from exo.shared.logging import logger from exo.shared.types.chunks import ( ErrorChunk, PrefillProgressChunk, @@ -87,64 +113,216 @@ async def responses_request_to_text_generation( ) for item in request.input: - if isinstance(item, ResponseInputMessage): - content = _extract_content(item.content) - if isinstance(item.content, list): - for part in item.content: - if isinstance(part, ResponseInputImagePart) and part.image_url: - url = part.image_url - if url.startswith(("http://", "https://")): - images.append(await fetch_image_url(url)) - else: - images.append(extract_base64_from_data_url(url)) - has_images = True - if item.role in ("user", "assistant", "developer"): - input_messages.append(InputMessage(role=item.role, content=content)) - if item.role == "system": - chat_template_messages.append( - {"role": "system", "content": content} - ) - elif has_images: - multimodal: list[dict[str, Any]] = [] + match item: + case ResponseInputMessage(): + content = _extract_content(item.content) if isinstance(item.content, list): for part in item.content: - if isinstance(part, ResponseInputImagePart): - multimodal.append({"type": "image"}) - elif hasattr(part, "text"): - multimodal.append({"type": "text", "text": part.text}) + if ( + isinstance(part, ResponseInputImagePart) + and part.image_url + ): + url = part.image_url + if url.startswith(("http://", "https://")): + images.append(await fetch_image_url(url)) + else: + images.append(extract_base64_from_data_url(url)) + has_images = True + if item.role in ("user", "assistant", "developer"): + input_messages.append( + InputMessage(role=item.role, content=content) + ) + if item.role == "system": + chat_template_messages.append( + {"role": "system", "content": content} + ) + elif has_images: + multimodal: list[dict[str, Any]] = [] + if isinstance(item.content, list): + for part in item.content: + if isinstance(part, ResponseInputImagePart): + multimodal.append({"type": "image"}) + elif hasattr(part, "text"): + multimodal.append( + {"type": "text", "text": part.text} + ) + chat_template_messages.append( + {"role": item.role, "content": multimodal} + ) + has_images = False + else: + chat_template_messages.append( + {"role": item.role, "content": content} + ) + case ( + FunctionCallInputItem() + | McpCallInputItem() + | CustomToolCallInputItem() + ): chat_template_messages.append( - {"role": item.role, "content": multimodal} + { + "role": "assistant", + "content": "", + "tool_calls": [ + { + "id": item.call_id, + "type": "function", + "function": { + "name": item.name, + "arguments": item.arguments, + }, + } + ], + } ) - has_images = False - else: + case ( + LocalShellCallInputItem() + | ShellCallInputItem() + | ComputerCallInputItem() + ): chat_template_messages.append( - {"role": item.role, "content": content} + { + "role": "assistant", + "content": "", + "tool_calls": [ + { + "id": item.call_id, + "type": "function", + "function": { + "name": item.type, + "arguments": json.dumps(item.action), + }, + } + ], + } ) - elif isinstance(item, FunctionCallInputItem): - chat_template_messages.append( - { - "role": "assistant", - "content": "", - "tool_calls": [ + case ApplyPatchCallInputItem(): + chat_template_messages.append( + { + "role": "assistant", + "content": "", + "tool_calls": [ + { + "id": item.call_id, + "type": "function", + "function": { + "name": "apply_patch", + "arguments": json.dumps({"patch": item.patch}), + }, + } + ], + } + ) + case ( + WebSearchCallInputItem() + | FileSearchCallInputItem() + | CodeInterpreterCallInputItem() + | ImageGenerationCallInputItem() + | ToolSearchCallInputItem() + ): + args: dict[str, Any] = {} + if isinstance(item, WebSearchCallInputItem): + args = {"query": item.query} + elif isinstance(item, FileSearchCallInputItem): + args = {"queries": item.queries} + elif isinstance(item, CodeInterpreterCallInputItem): + args = {"code": item.code} + elif isinstance(item, ImageGenerationCallInputItem): + args = {"prompt": item.prompt} + else: + args = {"query": item.query} + chat_template_messages.append( + { + "role": "assistant", + "content": "", + "tool_calls": [ + { + "id": item.call_id, + "type": "function", + "function": { + "name": item.type, + "arguments": json.dumps(args), + }, + } + ], + } + ) + case ( + FunctionCallOutputInputItem() + | LocalShellCallOutputInputItem() + | ShellCallOutputInputItem() + | ApplyPatchCallOutputInputItem() + | ComputerCallOutputInputItem() + | CustomToolCallOutputInputItem() + | ToolSearchOutputInputItem() + ): + output = ( + item.output + if isinstance(item.output, str) + else json.dumps(item.output) + ) + chat_template_messages.append( + { + "role": "tool", + "tool_call_id": item.call_id, + "content": output, + } + ) + case ReasoningInputItem(): + reasoning_text = "" + if item.content: + reasoning_text = "".join( + entry.get("text", "") for entry in item.content + ) + elif item.summary: + reasoning_text = "".join( + entry.get("text", "") for entry in item.summary + ) + if reasoning_text: + chat_template_messages.append( + {"role": "assistant", "content": reasoning_text} + ) + case CompactionInputItem(): + if item.summary: + chat_template_messages.append( + {"role": "system", "content": item.summary} + ) + case McpListToolsInputItem(): + tools_desc = ", ".join(t.get("name", "") for t in item.tools) + if tools_desc: + chat_template_messages.append( { - "id": item.call_id, - "type": "function", - "function": { - "name": item.name, - "arguments": item.arguments, - }, + "role": "system", + "content": f"Available MCP tools ({item.server_label}): {tools_desc}", } - ], - } - ) - else: - chat_template_messages.append( - { - "role": "tool", - "tool_call_id": item.call_id, - "content": item.output, - } - ) + ) + case McpApprovalRequestInputItem(): + chat_template_messages.append( + { + "role": "assistant", + "content": "", + "tool_calls": [ + { + "id": item.call_id, + "type": "function", + "function": { + "name": item.name, + "arguments": item.arguments, + }, + } + ], + } + ) + case McpApprovalResponseInputItem(): + chat_template_messages.append( + { + "role": "tool", + "tool_call_id": item.approval_request_id, + "content": f"{'Approved' if item.approve else 'Denied'}{': ' + item.reason if item.reason else ''}", + } + ) + case ItemReferenceInputItem(): + logger.info("Cannot handle ItemReferenceInputItem, skipping") input_value = ( input_messages diff --git a/src/exo/api/main.py b/src/exo/api/main.py index 3021d689..5635a409 100644 --- a/src/exo/api/main.py +++ b/src/exo/api/main.py @@ -1660,6 +1660,7 @@ class API: quantization=card.quantization, base_model=card.base_model, capabilities=card.capabilities, + context_length=card.context_length, ) for card in cards ] diff --git a/src/exo/api/types/openai_responses.py b/src/exo/api/types/openai_responses.py index b06593ac..0b747648 100644 --- a/src/exo/api/types/openai_responses.py +++ b/src/exo/api/types/openai_responses.py @@ -75,8 +75,228 @@ class FunctionCallOutputInputItem(BaseModel, frozen=True): status: ResponseStatus | None = None +class ReasoningInputItem(BaseModel, frozen=True): + type: Literal["reasoning"] = "reasoning" + id: str | None = None + summary: list[dict[str, Any]] | None = None + encrypted_content: str | None = None + content: list[dict[str, Any]] | None = None + status: ResponseStatus | None = None + + +class ComputerCallInputItem(BaseModel, frozen=True): + type: Literal["computer_call"] = "computer_call" + id: str | None = None + call_id: str = "" + action: dict[str, Any] = {} + status: ResponseStatus | None = None + + +class ComputerCallOutputInputItem(BaseModel, frozen=True): + type: Literal["computer_call_output"] = "computer_call_output" + id: str | None = None + call_id: str = "" + output: dict[str, Any] | str = "" + status: ResponseStatus | None = None + + +class WebSearchCallInputItem(BaseModel, frozen=True): + type: Literal["web_search_call"] = "web_search_call" + id: str | None = None + call_id: str = "" + query: str = "" + status: ResponseStatus | None = None + + +class FileSearchCallInputItem(BaseModel, frozen=True): + type: Literal["file_search_call"] = "file_search_call" + id: str | None = None + call_id: str = "" + queries: list[str] = [] + results: list[dict[str, Any]] | None = None + status: ResponseStatus | None = None + + +class CodeInterpreterCallInputItem(BaseModel, frozen=True): + type: Literal["code_interpreter_call"] = "code_interpreter_call" + id: str | None = None + call_id: str = "" + code: str = "" + results: list[dict[str, Any]] | None = None + status: ResponseStatus | None = None + + +class ImageGenerationCallInputItem(BaseModel, frozen=True): + type: Literal["image_generation_call"] = "image_generation_call" + id: str | None = None + call_id: str = "" + prompt: str = "" + result: dict[str, Any] | None = None + status: ResponseStatus | None = None + + +class LocalShellCallInputItem(BaseModel, frozen=True): + type: Literal["local_shell_call"] = "local_shell_call" + id: str | None = None + call_id: str = "" + action: dict[str, Any] = {} + status: ResponseStatus | None = None + + +class LocalShellCallOutputInputItem(BaseModel, frozen=True): + type: Literal["local_shell_call_output"] = "local_shell_call_output" + id: str | None = None + call_id: str = "" + output: str = "" + status: ResponseStatus | None = None + + +class ShellCallInputItem(BaseModel, frozen=True): + type: Literal["shell_call"] = "shell_call" + id: str | None = None + call_id: str = "" + action: dict[str, Any] = {} + status: ResponseStatus | None = None + + +class ShellCallOutputInputItem(BaseModel, frozen=True): + type: Literal["shell_call_output"] = "shell_call_output" + id: str | None = None + call_id: str = "" + output: str = "" + status: ResponseStatus | None = None + + +class ApplyPatchCallInputItem(BaseModel, frozen=True): + type: Literal["apply_patch_call"] = "apply_patch_call" + id: str | None = None + call_id: str = "" + patch: str = "" + status: ResponseStatus | None = None + + +class ApplyPatchCallOutputInputItem(BaseModel, frozen=True): + type: Literal["apply_patch_call_output"] = "apply_patch_call_output" + id: str | None = None + call_id: str = "" + output: str = "" + status: ResponseStatus | None = None + + +class ToolSearchCallInputItem(BaseModel, frozen=True): + type: Literal["tool_search_call"] = "tool_search_call" + id: str | None = None + call_id: str = "" + query: str = "" + status: ResponseStatus | None = None + + +class ToolSearchOutputInputItem(BaseModel, frozen=True): + type: Literal["tool_search_output"] = "tool_search_output" + id: str | None = None + call_id: str = "" + output: str = "" + status: ResponseStatus | None = None + + +class McpCallInputItem(BaseModel, frozen=True): + type: Literal["mcp_call"] = "mcp_call" + id: str | None = None + call_id: str = "" + name: str = "" + arguments: str = "" + server_label: str = "" + approval_request_id: str | None = None + error: str | None = None + output: str | None = None + status: ResponseStatus | None = None + + +class McpListToolsInputItem(BaseModel, frozen=True): + type: Literal["mcp_list_tools"] = "mcp_list_tools" + id: str | None = None + server_label: str = "" + tools: list[dict[str, Any]] = [] + error: str | None = None + status: ResponseStatus | None = None + + +class McpApprovalRequestInputItem(BaseModel, frozen=True): + type: Literal["mcp_approval_request"] = "mcp_approval_request" + id: str | None = None + call_id: str = "" + name: str = "" + arguments: str = "" + server_label: str = "" + status: ResponseStatus | None = None + + +class McpApprovalResponseInputItem(BaseModel, frozen=True): + type: Literal["mcp_approval_response"] = "mcp_approval_response" + id: str | None = None + approval_request_id: str = "" + approve: bool = True + reason: str = "" + status: ResponseStatus | None = None + + +class CustomToolCallInputItem(BaseModel, frozen=True): + type: Literal["custom_tool_call"] = "custom_tool_call" + id: str | None = None + call_id: str = "" + name: str = "" + arguments: str = "" + status: ResponseStatus | None = None + + +class CustomToolCallOutputInputItem(BaseModel, frozen=True): + type: Literal["custom_tool_call_output"] = "custom_tool_call_output" + id: str | None = None + call_id: str = "" + output: str = "" + status: ResponseStatus | None = None + + +class CompactionInputItem(BaseModel, frozen=True): + type: Literal["compaction"] = "compaction" + id: str | None = None + summary: str = "" + encrypted_content: str | None = None + status: ResponseStatus | None = None + + +class ItemReferenceInputItem(BaseModel, frozen=True): + type: Literal["item_reference"] = "item_reference" + id: str | None = None + + ResponseInputItem = ( - ResponseInputMessage | FunctionCallInputItem | FunctionCallOutputInputItem + ResponseInputMessage + | FunctionCallInputItem + | FunctionCallOutputInputItem + | ReasoningInputItem + | ComputerCallInputItem + | ComputerCallOutputInputItem + | WebSearchCallInputItem + | FileSearchCallInputItem + | CodeInterpreterCallInputItem + | ImageGenerationCallInputItem + | LocalShellCallInputItem + | LocalShellCallOutputInputItem + | ShellCallInputItem + | ShellCallOutputInputItem + | ApplyPatchCallInputItem + | ApplyPatchCallOutputInputItem + | ToolSearchCallInputItem + | ToolSearchOutputInputItem + | McpCallInputItem + | McpListToolsInputItem + | McpApprovalRequestInputItem + | McpApprovalResponseInputItem + | CustomToolCallInputItem + | CustomToolCallOutputInputItem + | CompactionInputItem + | ItemReferenceInputItem ) diff --git a/src/exo/shared/models/model_cards.py b/src/exo/shared/models/model_cards.py index 0883d3e1..50da8125 100644 --- a/src/exo/shared/models/model_cards.py +++ b/src/exo/shared/models/model_cards.py @@ -134,6 +134,7 @@ class ModelCard(CamelCaseModel): quantization: str = "" base_model: str = "" capabilities: list[str] = [] + context_length: int = 0 uses_cfg: bool = False trust_remote_code: bool = True is_custom: bool = False @@ -202,6 +203,7 @@ class ModelCard(CamelCaseModel): hidden_size=config_data.hidden_size or 0, supports_tensor=config_data.supports_tensor, num_key_value_heads=config_data.num_key_value_heads, + context_length=config_data.max_position_embeddings, tasks=[ModelTask.TextGeneration], trust_remote_code=False, is_custom=True, @@ -240,6 +242,7 @@ class ConfigData(BaseModel): "decoder_layers", ) ) + max_position_embeddings: int = 0 vision: VisionCardConfig | None = None @property @@ -269,6 +272,7 @@ class ConfigData(BaseModel): "architectures", "hidden_size", "num_key_value_heads", + "max_position_embeddings", "num_hidden_layers", "num_layers", "n_layer", diff --git a/src/exo/worker/engines/mlx/generator/batch_generate.py b/src/exo/worker/engines/mlx/generator/batch_generate.py index 303609a4..a6d9646b 100644 --- a/src/exo/worker/engines/mlx/generator/batch_generate.py +++ b/src/exo/worker/engines/mlx/generator/batch_generate.py @@ -132,6 +132,8 @@ class ExoBatchGenerator: vision_processor=self.vision_processor, tokenizer=self.tokenizer, model=self.model, + model_id=task_params.model, + task_params=task_params, ) except Exception: logger.opt(exception=True).warning( diff --git a/src/exo/worker/engines/mlx/generator/generate.py b/src/exo/worker/engines/mlx/generator/generate.py index d49ff58c..043a822f 100644 --- a/src/exo/worker/engines/mlx/generator/generate.py +++ b/src/exo/worker/engines/mlx/generator/generate.py @@ -508,6 +508,8 @@ def mlx_generate( vision_processor=vision_processor, tokenizer=tokenizer, model=model, + model_id=task.model, + task_params=task, ) except Exception: logger.opt(exception=True).warning( diff --git a/src/exo/worker/engines/mlx/utils_mlx.py b/src/exo/worker/engines/mlx/utils_mlx.py index 4ee643b9..e84a1934 100644 --- a/src/exo/worker/engines/mlx/utils_mlx.py +++ b/src/exo/worker/engines/mlx/utils_mlx.py @@ -503,11 +503,39 @@ def _needs_dsml_encoding(task_params: TextGenerationTaskParams) -> bool: return "deepseek-v3.2" in task_params.model.lower() -def apply_chat_template( +def consolidate_system_messages( + messages: list[dict[str, Any]], +) -> list[dict[str, Any]]: + """ + System messages almost exclusively must go at the start of a message + and there must only be a single one. + + Also, Codex sends "developer" messages which are just system prompts. + """ + system_parts: list[str] = [] + non_system: list[dict[str, Any]] = [] + for msg in messages: + if msg.get("role") in ("system", "developer"): + content = cast(str, msg.get("content", "")) + if content: + system_parts.append(content) + else: + non_system.append(msg) + formatted_messages = non_system + if system_parts: + formatted_messages.insert( + 0, {"role": "system", "content": "\n".join(system_parts)} + ) + return formatted_messages + + +def render_chat_template( tokenizer: TokenizerWrapper, + messages: list[dict[str, Any]], task_params: TextGenerationTaskParams, ) -> str: - """Convert TextGenerationTaskParams to a chat template prompt. + """ + Convert TextGenerationTaskParams to a chat template prompt. Converts the internal format (input + instructions) to a messages list that can be processed by the tokenizer's chat template. @@ -515,23 +543,7 @@ def apply_chat_template( When chat_template_messages is available (from Chat Completions API), uses those directly to preserve tool_calls, thinking, and other fields. """ - formatted_messages: list[dict[str, Any]] = [] - if task_params.chat_template_messages is not None: - # Use pre-formatted messages that preserve tool_calls, thinking, etc. - formatted_messages = list(task_params.chat_template_messages) - else: - # Add system message (instructions) if present - if task_params.instructions: - formatted_messages.append( - {"role": "system", "content": task_params.instructions} - ) - - # Convert input to messages - for msg in task_params.input: - if not msg.content: - logger.warning("Received message with empty content, skipping") - continue - formatted_messages.append({"role": msg.role, "content": msg.content}) + formatted_messages = consolidate_system_messages(messages) # For assistant prefilling, append content after templating to avoid a closing turn token. partial_assistant_content: str | None = None @@ -592,6 +604,30 @@ def apply_chat_template( if partial_assistant_content: prompt += partial_assistant_content + return prompt + + +def apply_chat_template( + tokenizer: TokenizerWrapper, + task_params: TextGenerationTaskParams, +) -> str: + messages: list[dict[str, Any]] = [] + if task_params.chat_template_messages is not None: + # Use pre-formatted messages that preserve tool_calls, thinking, etc. + messages = list(task_params.chat_template_messages) + else: + # Add system message (instructions) if present + if task_params.instructions: + messages.append({"role": "system", "content": task_params.instructions}) + + # Convert input to messages + for msg in task_params.input: + if not msg.content: + logger.warning("Received message with empty content, skipping") + continue + messages.append({"role": msg.role, "content": msg.content}) + + prompt = render_chat_template(tokenizer, messages, task_params) logger.info(prompt) return prompt diff --git a/src/exo/worker/engines/mlx/vision.py b/src/exo/worker/engines/mlx/vision.py index f0839b21..49cb024d 100644 --- a/src/exo/worker/engines/mlx/vision.py +++ b/src/exo/worker/engines/mlx/vision.py @@ -25,8 +25,12 @@ from exo.download.download_utils import build_model_path from exo.shared.models.model_cards import VisionCardConfig from exo.shared.types.common import ModelId from exo.shared.types.mlx import Model +from exo.shared.types.text_generation import TextGenerationTaskParams from exo.worker.engines.mlx.cache import encode_prompt -from exo.worker.engines.mlx.utils_mlx import fix_unmatched_think_end_tokens +from exo.worker.engines.mlx.utils_mlx import ( + fix_unmatched_think_end_tokens, + render_chat_template, +) from exo.worker.runner.bootstrap import logger @@ -86,15 +90,9 @@ def build_vision_prompt( chat_template_messages: list[dict[str, Any]], n_tokens_per_image: list[int], image_token: str, + task_params: TextGenerationTaskParams, ) -> str: - logger.info( - f"Vision prompt messages: {[{k: (v[:50] if isinstance(v, str) else v) for k, v in m.items()} for m in chat_template_messages]}" # type: ignore - ) - prompt: str = tokenizer.apply_chat_template( - chat_template_messages, - tokenize=False, - add_generation_prompt=True, - ) + prompt = render_chat_template(tokenizer, chat_template_messages, task_params) image_idx = 0 result: list[str] = [] @@ -498,6 +496,7 @@ class VisionProcessor: chat_template_messages: list[dict[str, Any]], tokenizer: TokenizerWrapper, model: Model, + task_params: TextGenerationTaskParams, ) -> VisionResult: logger.info(f"Vision pipeline: {len(images)} image(s)") @@ -529,6 +528,7 @@ class VisionProcessor: formatted_messages, n_tokens_per_image, image_token, + task_params, ) logger.info( @@ -572,6 +572,8 @@ def prepare_vision( vision_processor: VisionProcessor, tokenizer: TokenizerWrapper, model: Model, + model_id: ModelId, + task_params: TextGenerationTaskParams, ) -> VisionResult | None: if not images: return None @@ -586,4 +588,5 @@ def prepare_vision( chat_template_messages=chat_template_messages, tokenizer=tokenizer, model=model, + task_params=task_params, )