Skip to main content

ModelSchema

Struct ModelSchema 

Source
pub struct ModelSchema {
Show 20 fields pub id: String, pub name: String, pub provider: String, pub family: String, pub version: String, pub capabilities: Vec<ModelCapability>, pub context_length: usize, pub max_output_tokens: Option<usize>, pub param_count: String, pub quantization: Option<Quantization>, pub performance: PerformanceEnvelope, pub cost: CostModel, pub source: ModelSource, pub tags: Vec<String>, pub supported_params: Vec<GenerateParam>, pub public_benchmarks: Vec<BenchmarkScore>, pub trust_tier: TrustTier, pub deprecated: bool, pub available: bool, pub weights_ready: bool,
}
Expand description

The full declarative schema for a model.

Analogous to ToolSchema — describes what a model is, what it can do, and how to access it. The router uses this for constraint-based filtering and cold-start scoring before observed performance data is available.

Fields§

§id: String

Unique identifier: “provider/model-name:variant” (e.g., “qwen/qwen3-4b:q4_k_m”).

§name: String

Human-readable display name.

§provider: String

Provider (qwen, openai, anthropic, google, meta, ollama, custom).

§family: String

Model family for grouping (qwen3, gpt-4, claude-4, llama-3).

§version: String

Semantic version or checkpoint label.

§capabilities: Vec<ModelCapability>

What this model can do — ordered by primary capability first.

§context_length: usize

Context window in tokens.

§max_output_tokens: Option<usize>

Per-model maximum OUTPUT tokens the provider will return in one response. None = unknown; callers fall back to effective_max_output() which derives a fraction of context_length.

§param_count: String

Parameter count as human-readable string (e.g., “4B”, “30B (3B active)”).

§quantization: Option<Quantization>

How the weights are quantized, if at all. None for remote models and for local ones whose source declared nothing. See Quantization — this accepts the legacy bare-string form on the wire.

§performance: PerformanceEnvelope

Declared performance envelope (initial estimate, overridden by observed data).

§cost: CostModel

Cost structure.

§source: ModelSource

How to access this model.

§tags: Vec<String>

Free-form tags for filtering (e.g., “fast”, “multilingual”, “moe”).

§supported_params: Vec<GenerateParam>

Supported generation parameters. The inference layer strips any parameter not in this set before sending to the API. Empty = all supported.

§public_benchmarks: Vec<BenchmarkScore>

Public benchmark scores as published by the model provider or reproduced on a public leaderboard (MMLU-Pro, GPQA-Diamond, SWE-bench, HumanEval, etc.). The built-in catalog ships this empty — population is a curation step, not a code change. See BenchmarkScore for the field shape and the 0.0–1.0 scoring convention.

§trust_tier: TrustTier

How much the project vouches for this model. The built-in catalog is Curated. Deserialization retains the legacy Curated default, so every user-controlled ingestion boundary must call Self::mark_user_registered before persistence or registration. Gates auto-apply (task #8) and this is surfaced in recommendation rationale.

§deprecated: bool

Superseded models stay listed if installed but are excluded from fresh recommendations. #[serde(default)] → not deprecated.

§available: bool

Whether this model is currently available (downloaded / reachable). Not serialized — computed at runtime.

§weights_ready: bool

Whether this model can be used right now, without a download.

Deliberately narrower than Self::available, which for a local MLX model is true as soon as an hf_repo is declared — ensure_local() lazy-downloads on first use, so a declared repo is “functionally available” (see #164). That is the right default for open-ended work and wrong for work on a deadline: a step with a bounded budget that picks a model it must first fetch spends the whole budget downloading and fails. That is exactly how car code’s 120s contract derivation became unusable on a machine with no local weights (Parslee-ai/car#638).

Callers express the requirement with crate::IntentHint::require_ready; this is the per-candidate fact that hint filters on. Recomputed on every registration, so a cached schema can’t carry a stale value.

Implementations§

Source§

impl ModelSchema

Source

pub fn mark_user_registered(&mut self)

Mark a schema as user-controlled rather than project-vetted.

This is intentionally separate from serde’s legacy default: old built-in and test fixtures omit trust_tier and must continue to deserialize, while models.json, CLI imports, and daemon models.register must never inherit Curated merely because a caller omitted the field or supplied a forged value.

Source

pub fn has_capability(&self, cap: ModelCapability) -> bool

Check if this model has a given capability.

Source

pub fn available_now(&self) -> bool

Live availability for credential-backed providers. The catalog field is a startup snapshot; Settings/OAuth changes must affect the next list and route without a daemon restart.

Source

pub fn cache_rates(&self) -> CacheRates

Prompt-cache economics for this model, derived from its remote protocol. Local / non-remote models have no remote prompt cache, so their cache rates are inert (CacheRates::NONE).

Source

pub fn vendor(&self) -> Option<&str>

The organization whose model this is, when that can be honestly known.

Answers one question — could two models be expected to fail the same way? — so it is deliberately conservative. None means UNKNOWABLE, not “none”, and callers must treat it as “cannot tell” rather than folding it into a count of distinct vendors.

NOT Self::provider, which means four different things depending on which path built the schema:

  • curated remote rows — the real vendor (openai, anthropic);
  • OpenRouter and the Parslee gateway — the AGGREGATOR, so three vendors behind one gateway all report openrouter/parslee and one vendor reached two ways reports as two;
  • a HuggingFace-derived row — the repo ORG that uploaded it, so unsloth/Qwen3 and mlx-community/Qwen3 are the same weights under two “vendors”;
  • a discovered local-server row — a guess from the model name.

Only the first is a vendor, so only the first is reported. NOT family either — that is the model line, so claude-4.6 and claude-4.8 read as different and are both Anthropic.

Source

pub fn is_local(&self) -> bool

Check if this model is local (runs on-device).

Source

pub fn downloads_weights(&self) -> bool

Whether this model has weights CAR fetches to disk before it can be used — i.e. whether “is it installed?” is a question with an answer.

Three predicates in this area are easy to conflate, and conflating them is what Parslee-ai/car#894 was about:

  • is_localowned on this machine. True for WindowsSpeech (the OS owns the voices), AppleFoundationModels (the OS owns the weights), and CAR-managed sources. An external VllmMlx endpoint is remote even when its URL happens to be loopback.
  • weights_readythe weights are on disk now. Only meaningful when this predicate is true; for everything else the registry sets it to true as a “nothing blocks an attempt” sentinel, which reads as “installed” if taken literally.
  • downloads_weights (this one) — there is something to install at all. Use it to decide whether an install/download status should be reported, then use weights_ready for the status itself.

Rendering weights_ready without this gate is what made windows/speech-synthesis:os claim INSTALLED yes while car doctor said Models: none installed, and made apple/foundation:default and the vllm-mlx/* rows claim INSTALLED no for models that install nothing.

Written as an exhaustive match rather than matches! so that adding a ModelSource variant is a compile error here instead of a silently wrong answer in the CLI.

Source

pub fn has_installed_weights(&self) -> bool

Whether a CAR-downloadable artifact is physically present now. General runtime availability and OS/server-owned weights are not an installation claim.

Source

pub fn decodes_in_process(&self) -> bool

Whether CAR decodes this model in its own process, token by token, through the shared decode loop.

Narrower than is_local on purpose. is_local also covers CAR-managed vLLM-MLX and the speech backends. Those do not spend an output-token budget as this process’s wall clock, so they must keep the remote treatment. Getting that distinction wrong takes the anti-truncation budget away from vLLM-MLX, which is the documented way to get structured tool calls out of a local model. (car#851)

Source

pub fn is_delegated(&self) -> bool

Check if this model delegates inference to a host-registered runner (closes Parslee-ai/car-releases#24).

Source

pub fn is_codex_cli(&self) -> bool

Check if this model runs one tool-free turn through codex exec.

Source

pub fn is_mlx(&self) -> bool

Check if this model uses the MLX backend.

Source

pub fn is_foundation_models(&self) -> bool

Check if this model routes to Apple’s on-device FoundationModels framework. True only for ModelSource::AppleFoundationModels; callers must still verify runtime availability before dispatch (the schema can describe the model on any host, but execution requires macOS 26+ on Apple Silicon).

Source

pub fn is_os_provided(&self) -> bool

Whether the operating system owns the implementation and its memory. These rows have no CAR-downloadable artifact and no local-model memory figure to compare with the admission budget.

Source

pub fn is_vllm_mlx(&self) -> bool

Check if this model uses vLLM-MLX backend.

Source

pub fn is_car_managed_vllm_mlx(&self) -> bool

Whether CAR, rather than an independently managed endpoint, owns the vLLM-MLX child process and its physical weight allocation. The existing HTTP VllmMlx contract remains external/server-owned. A supervised source must opt in explicitly and provide an already-installed local model path in model_name; it is then replaced with a loopback HTTP endpoint only after admission and a successful readiness ACK.

Source

pub fn requires_apple_silicon(&self) -> bool

Whether a CAR/OS-owned model can only run on Apple Silicon (Metal). External vLLM-MLX endpoints own their hardware and are not constrained by the client machine’s accelerator.

Source

pub fn is_remote(&self) -> bool

Check if this model is remote (requires API call).

Source

pub fn all_api_key_envs(&self) -> Vec<String>

Collect all API key env var names for this model (primary + extras). Returns empty vec for non-remote models.

Source

pub fn size_mb(&self) -> u64

Get the size in MB (from cost model or 0 if unknown).

Source

pub fn ram_mb(&self) -> u64

Get the RAM requirement in MB (from cost model, falls back to size_mb).

Source

pub fn cost_per_1k_output(&self) -> f64

Estimated cost per 1K output tokens in USD. Returns 0.0 for local models.

Source

pub fn effective_max_output(&self) -> usize

The per-turn output-token ceiling to use when the caller didn’t specify one. Prefers the registry-declared max_output_tokens; otherwise derives a quarter of the context window, clamped to a sane [4096, 32768] band so a 1M-context model doesn’t request a 250K-token response the API rejects and a tiny 8K model doesn’t get an absurdly small ceiling. (Registry value first, computed fallback second — mirrors a provider lookup with a derived default.)

Trait Implementations§

Source§

impl Clone for ModelSchema

Source§

fn clone(&self) -> ModelSchema

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ModelSchema

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for ModelSchema

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl From<&ModelSchema> for ModelInfo

Source§

fn from(s: &ModelSchema) -> Self

Converts to this type from the input type.
Source§

impl Serialize for ModelSchema

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more