Skip to content

Engine API

LexiSuite edited this page Nov 12, 2026 · 1 revision

LexiEngine native HTTP API

LexiEngine serves one resident text model through /v1/chat/completions, /v1/completions, and /v1/responses. GET /v1/models lists its declared HTTP names. Declaring names does not load additional models, change the weights, or permit arbitrary client-supplied names.

Server launch options

lexi-engine serve -m /models/model.gguf \
  --alias main --alias client-main \
  --chat-template-file /models/chat.jinja \
  --chat-template-kwargs '{"reasoning_effort":"xhigh","enable_thinking":true}' \
  --reasoning-format auto \
  --temp 1.0 --top-p 0.95 --top-k 20 --min-p 0 --n-predict 2048

--alias NAME is repeatable. The first name is the resident model's public ID; additional names are accepted as exact matches and listed separately by GET /v1/models. Omitting model from a supported request selects the resident model. Names that were not declared remain a 400 with requested model is not loaded. The default name, if no alias is given, is the model identity normally reported by the loader. Aliases are not a second model and cannot be used to bypass authorization.

--chat-template-file PATH overrides the tokenizer.chat_template embedded in the GGUF. The file must be valid UTF-8, nonempty, no more than 256 KiB, and syntactically parseable by the sandboxed template renderer. The server validates it before listening and refuses a malformed or unreadable file. This option affects chat prompt rendering and chat input-token counting; it does not replace the model tokenizer or weights.

--chat-template-kwargs JSON accepts a JSON object of server-default template variables. Chat request chat_template_kwargs overrides matching defaults; reserved message/BOS/EOS keys and invalid value types remain rejected. For example, a template that consumes reasoning_effort can receive "xhigh" from these variables. An arbitrary variable has an effect only when the chosen template actually uses it. There is no separate mechanism that forces a model to generate hidden reasoning.

Sampling defaults apply to requests that omit the respective field: --temp (0–2), --top-p (0–1), --top-k (0–100000), --min-p (0–1) and --n-predict (1–131072). Explicit request settings take precedence, including explicit zero values; request generation limits and context ceilings are still enforced. Without these switches, existing server sampling defaults remain unchanged.

Reasoning response format

--reasoning-format auto is the default. For chat output that opens <think>...</think>, LexiEngine puts the thought text in choices[0].message.reasoning_content and the visible answer alone in choices[0].message.content. Streaming chat emits the corresponding delta.reasoning_content and delta.content frames. Delimiters split across generation events are held back so they do not appear in either field. When generation stops before </think>, content is empty. The previously supported thought-channel template also continues to be separated.

--reasoning-format none disables this output separation and preserves the raw generated text in content, including thought delimiters. This is an output-format selection, not a switch to disable reasoning in the model. To disable the template's thinking mode, use enable_thinking:false when the template supports it.

Example nonstreaming response excerpt:

{
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "reasoning_content": "intermediate text",
      "content": "final answer"
    }
  }]
}

The reasoning separation applies to the native chat-completions route; non-chat compatibility endpoints retain their own output contracts. Structured/tool outputs continue to be verified before client-visible structured events are emitted. A template may produce other, currently unsupported reasoning formats; they are not inferred or silently relabeled. None of these options guarantees a particular model capability, performance, or device-backend qualification.

Reasoning level in a request

A chat request may carry reasoning_effort (none, minimal, low, medium, high, xhigh). For a model whose chat template has a thinking switch, any level other than none turns thinking on and none turns it off. For a model whose template cannot think, a level other than none is answered with 501: the engine does not invent reasoning.

Conversation history

An assistant message in the history may carry the reasoning_content it was returned with. It is accepted and left out of the prompt: an earlier turn's thinking is not replayed to the model. On any other role the field is refused. A tool message may carry the function's name beside its tool_call_id; the id is what pairs it with its call.

Tools

When the chat template in use renders tools itself (most current models' templates do), the request's tools, earlier assistant tool_calls and tool results are given to the template in its own terms, so the model sees its trained format. Calls are read in the JSON form (<tool_call>{"name":...,"arguments":{...}}</tool_call>) and in the function form (<tool_call><function=NAME><parameter=KEY>VALUE</parameter></function></tool_call>); in the function form a value is text when the tool's schema says the parameter is a string and is otherwise read as JSON when it is JSON. With a template that has no tool support, and for a request that forces one named tool, the engine uses its own tool prompt.

Every call is verified against its tool's schema before it is returned. Output that only looks like a call is returned as the assistant's text, unless tool_choice required a call, in which case it is an error.

Schemas. A tool marked "strict": true must use a closed object schema with all properties required, and is refused otherwise. A tool that is not strict may use ordinary JSON Schema: an object without additionalProperties, default, a nullable anyOf, pattern, format, numeric and length bounds, $ref. What the engine cannot enforce while decoding is widened to the nearest thing it can, never narrowed, with one exception that follows common practice: an object that lists properties and says nothing about others accepts only the listed ones. The model is shown the schema as the client wrote it.

Waiting for a busy slot

--queue-wait SECONDS (default 0) makes a generation request wait up to that long for a free slot instead of being answered 429 inference_busy at once. A client that sends two requests at the same moment to a one-slot server then has both answered, one after the other.

Clone this wiki locally