Skip to content

API reference

Auto-generated from docstrings via mkdocstrings. Source of truth remains the code in src/laya_serve/.

App

laya_serve.app

FastAPI application factory.

Endpoints (Jev-compatible):

  • POST /v1/systemone — evaluate state + questions, return typed answers.
  • GET /v1/models — list servable model names/aliases.
  • GET /healthz — liveness probe (not part of the Jev API).

Errors are always Jev-shaped ({"error": {"message", "field"}}): 401 bad key, 422 validation, 529 transient overload (with Retry-After), 500 unexpected backend failure.

AuthError

Bases: Exception

Raised when bearer auth fails; handled as a Jev-shaped 401.

Source code in src/laya_serve/app.py
34
35
36
37
class AuthError(Exception):
    """Raised when bearer auth fails; handled as a Jev-shaped ``401``."""

    pass

Schemas

laya_serve.schemas

Jev-compatible Pydantic v2 schemas for the SystemOne API.

Mirrors POST /v1/systemone from the TypeSafe docs:

  • Request: {state, model, questions} where each question is one of choice / score / noul.
  • Response: {model, answers, usage} with typed answers keyed by the caller-chosen question ids.

Wire format notes:

  • Score probabilities / legend keys are strings on the wire ({"0": ...}); the Python SDK exposes them as ints. This server speaks the HTTP wire format.
  • instructions and criteria descriptions accept str | dict | list (structured prompts); dict/list values are rendered by the backend.

SystemOneRequest

Bases: BaseModel

POST /v1/systemone request body.

Source code in src/laya_serve/schemas.py
83
84
85
86
87
88
89
90
class SystemOneRequest(BaseModel):
    """``POST /v1/systemone`` request body."""

    model_config = ConfigDict(extra="forbid")

    state: StateT
    model: str = Field(min_length=1)
    questions: Annotated[dict[str, QuestionT], Field(min_length=1)]

SystemOneResponse

Bases: BaseModel

POST /v1/systemone response body.

Source code in src/laya_serve/schemas.py
132
133
134
135
136
137
138
139
class SystemOneResponse(BaseModel):
    """``POST /v1/systemone`` response body."""

    model_config = ConfigDict(extra="forbid")

    model: str
    answers: dict[str, AnswerT]
    usage: Usage

Settings

laya_serve.settings

Runtime configuration, sourced from environment variables.

All variables use the LAYA_SERVE_ prefix, e.g. LAYA_SERVE_PRELOAD=true.

Settings

Bases: BaseSettings

Source code in src/laya_serve/settings.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_prefix="LAYA_SERVE_", extra="ignore")

    # Model id reported in the ``model`` response field.
    serving_model: str = "laya-english"
    # Additional model names accepted in the request ``model`` field,
    # beyond the built-in Jev family (comma-separated via env).
    extra_models: str = ""

    @property
    def extra_models_set(self) -> frozenset[str]:
        """Parsed :attr:`extra_models` as a set of names."""
        return frozenset(part.strip() for part in self.extra_models.split(",") if part.strip())

    # Inference backend: "laya" (real weights) or "fake" (deterministic,
    # weight-free answers for tests and local dev).
    backend: str = "fake"

    # Passed through to the Laya Router when backend="laya".
    device: str | None = None
    max_loaded: int = 1
    preload: bool = False

    # When set, clients must send ``Authorization: Bearer <api_key>``.
    # Unset means no auth (local dev default).
    api_key: str | None = None

extra_models_set property

Parsed :attr:extra_models as a set of names.

Service

laya_serve.service

Application service: orchestrates validation, inference, and compat shaping.

enforce_budgets(state, questions, backend)

Fail fast with 422 when the request exceeds the backend's token budgets.

Compares backend.count(state, questions) against the backend's max_total_tokens / max_state_question_tokens (Jev: 64k total, 32k state+longest-question). Backends that predate the budget interface skip enforcement. A broken counter fails open (warn + skip) so a counting bug can never turn a small request into a 500.

Source code in src/laya_serve/service.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
def enforce_budgets(state: Any, questions: dict[str, dict[str, Any]], backend: Backend) -> None:
    """Fail fast with ``422`` when the request exceeds the backend's token budgets.

    Compares ``backend.count(state, questions)`` against the backend's
    ``max_total_tokens`` / ``max_state_question_tokens`` (Jev: 64k total,
    32k state+longest-question). Backends that predate the budget
    interface skip enforcement. A broken counter fails open (warn + skip)
    so a counting bug can never turn a small request into a ``500``.
    """
    count = getattr(backend, "count", None)
    max_total = getattr(backend, "max_total_tokens", None)
    max_longest = getattr(backend, "max_state_question_tokens", None)
    if not callable(count) or max_total is None or max_longest is None:
        return
    try:
        total, state_longest = (int(n) for n in count(state, questions))
    except Exception:
        logger.warning("budget count failed; skipping enforcement", exc_info=True)
        return
    if state_longest > max_longest:
        raise compat.CompatError(
            f"context budget exceeded: state plus longest question is ~{state_longest} "
            f"tokens (limit {max_longest})",
            field="questions",
        )
    if total > max_total:
        raise compat.CompatError(
            f"context budget exceeded: state plus all questions is ~{total} tokens "
            f"(limit {max_total})",
            field="questions",
        )

evaluate(request, backend, settings)

Run one SystemOne request and return a Jev-shaped response dict.

Source code in src/laya_serve/service.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
def evaluate(request: SystemOneRequest, backend: Backend, settings: Settings) -> dict[str, Any]:
    """Run one SystemOne request and return a Jev-shaped response dict."""
    serving_model = compat.resolve_model(
        request.model, backend.serving_model, settings.extra_models_set
    )
    questions = request.model_dump(mode="json", exclude_none=False)["questions"]
    enforce_budgets(request.state, questions, backend)
    try:
        raw = backend.predict(request.state, questions)
    except ValueError as exc:
        mapped = _as_budget_error(exc)
        if mapped is exc:
            raise
        raise mapped from exc
    return compat.shape_response(
        questions,
        raw["answers"],
        raw.get("usage", {}),
        serving_model,
    )

list_models(settings, backend)

Return the models listing: the serving checkpoint plus Jev aliases.

Source code in src/laya_serve/service.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def list_models(settings: Settings, backend: Backend) -> dict[str, Any]:
    """Return the models listing: the serving checkpoint plus Jev aliases."""
    from .schemas import ModelsResponse

    cards = [
        {
            "name": backend.serving_model,
            "description": "Laya decision model served with a Jev-compatible API.",
            "release_date": "unknown",
        }
    ]
    for alias in sorted(compat.JEV_KNOWN_MODELS | settings.extra_models_set):
        if alias == backend.serving_model:
            continue
        cards.append(
            {
                "name": alias,
                "description": f"Alias resolving to {backend.serving_model}.",
                "release_date": "unknown",
            }
        )
    return ModelsResponse.model_validate({"models": cards}).model_dump(mode="json")

Compat

laya_serve.compat

Translate raw Laya backend payloads into the Jev wire format.

Known divergences between Laya's Agent.system_one output and Jev (verified against laya/agent.py and docs.typesafe.ai/api.md):

  1. Laya attaches action: {act_probability} to every answer; Jev has no such field. Stripped here.
  2. Laya returns confidence on noul answers; Jev noul answers carry only {type, noul}. Stripped here.
  3. Laya reports model: "laya-rl-agent"; Jev echoes the resolved versioned model id. The caller supplies the id to report.
  4. Laya always reports output_tokens: 0; Jev reports a (free but nonzero) count. Preserved as-is and documented — this layer does not invent token counts.

All functions here are pure and backend-agnostic: they operate on plain dicts, so they are unit-testable without model weights.

CompatError

Bases: ValueError

Raised when a backend payload cannot be shaped into a Jev answer.

Source code in src/laya_serve/compat.py
48
49
50
51
52
53
class CompatError(ValueError):
    """Raised when a backend payload cannot be shaped into a Jev answer."""

    def __init__(self, message: str, field: str | None = None) -> None:
        super().__init__(message)
        self.field = field

resolve_model(requested, serving_model, extra_models=frozenset())

Validate the requested model and return the id to report.

Known Jev names (plus operator-configured extras) resolve to serving_model — the checkpoint actually answering, e.g. "laya-english". Unknown names raise :class:CompatError.

Source code in src/laya_serve/compat.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def resolve_model(
    requested: str, serving_model: str, extra_models: frozenset[str] = frozenset()
) -> str:
    """Validate the requested ``model`` and return the id to report.

    Known Jev names (plus operator-configured extras) resolve to
    ``serving_model`` — the checkpoint actually answering, e.g.
    ``"laya-english"``. Unknown names raise :class:`CompatError`.
    """
    if requested in JEV_KNOWN_MODELS or requested in extra_models or requested == serving_model:
        return serving_model
    raise CompatError(
        f"unknown model {requested!r}; expected a Jev model name or the serving model {serving_model!r}",
        field="model",
    )

shape_choice(question_id, raw, options)

Shape a raw choice answer; drops Laya-only action.

Source code in src/laya_serve/compat.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
def shape_choice(question_id: str, raw: dict[str, Any], options: list[str]) -> ChoiceAnswer:
    """Shape a raw ``choice`` answer; drops Laya-only ``action``."""
    choice = raw.get("choice")
    if choice not in options:
        raise CompatError(
            f"choice answer {question_id!r} selected {choice!r}, which is not one of {options!r}",
            field=f"answers.{question_id}.choice",
        )
    probs = raw.get("probabilities", {})
    if set(probs) != set(options):
        raise CompatError(
            f"choice answer {question_id!r} probabilities cover {sorted(probs)!r}, expected {options!r}",
            field=f"answers.{question_id}.probabilities",
        )
    return ChoiceAnswer(
        type="choice",
        choice=choice,
        probabilities={
            opt: _clamp01(probs[opt], f"answers.{question_id}.probabilities.{opt}")
            for opt in options
        },
        confidence=_clamp01(raw.get("confidence"), f"answers.{question_id}.confidence"),
    )

shape_noul(question_id, raw)

Shape a raw noul answer; drops Laya-only confidence/action.

Source code in src/laya_serve/compat.py
83
84
85
86
87
88
89
def shape_noul(question_id: str, raw: dict[str, Any]) -> NoulAnswer:
    """Shape a raw ``noul`` answer; drops Laya-only ``confidence``/``action``."""
    if "noul" not in raw:
        raise CompatError(
            f"noul answer {question_id!r} is missing 'noul'", field=f"answers.{question_id}"
        )
    return NoulAnswer(type="noul", noul=_clamp01(raw["noul"], f"answers.{question_id}.noul"))

shape_response(request_questions, raw_answers, usage, serving_model)

Shape a full backend result into a Jev response dict (validated by caller).

request_questions are the validated question dicts (with type and criteria); they define the expected answer shapes. raw_answers is the backend's per-question output. Unknown/extra backend keys (action, routing) are ignored.

Source code in src/laya_serve/compat.py
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
def shape_response(
    request_questions: dict[str, dict[str, Any]],
    raw_answers: dict[str, dict[str, Any]],
    usage: dict[str, Any],
    serving_model: str,
) -> dict[str, Any]:
    """Shape a full backend result into a Jev response dict (validated by caller).

    ``request_questions`` are the *validated* question dicts (with ``type``
    and ``criteria``); they define the expected answer shapes. ``raw_answers``
    is the backend's per-question output. Unknown/extra backend keys
    (``action``, ``routing``) are ignored.
    """
    if set(raw_answers) != set(request_questions):
        raise CompatError(
            f"backend answered {sorted(raw_answers)!r}, expected {sorted(request_questions)!r}",
            field="answers",
        )
    answers: dict[str, Any] = {}
    for qid, qdef in request_questions.items():
        raw = raw_answers[qid]
        qtype = qdef["type"]
        if qtype == "noul":
            answers[qid] = shape_noul(qid, raw)
        elif qtype == "choice":
            criteria = qdef["criteria"]
            options = list(criteria) if isinstance(criteria, dict) else list(criteria)
            answers[qid] = shape_choice(qid, raw, options)
        elif qtype == "score":
            answers[qid] = shape_score(qid, raw, list(qdef["criteria"]))
        else:  # pragma: no cover - schema validation rejects this first
            raise CompatError(f"unknown question type {qtype!r}", field=f"questions.{qid}.type")
    response = SystemOneResponse(
        model=serving_model,
        answers=answers,
        usage=Usage(
            input_tokens=max(0, int(usage.get("input_tokens", 0))),
            output_tokens=max(0, int(usage.get("output_tokens", 0))),
        ),
    )
    return response.model_dump(mode="json", exclude_none=False)

shape_score(question_id, raw, levels)

Shape a raw score answer with stringified level keys; drops action.

Source code in src/laya_serve/compat.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
def shape_score(
    question_id: str,
    raw: dict[str, Any],
    levels: list[StructuredText],
) -> ScoreAnswer:
    """Shape a raw ``score`` answer with stringified level keys; drops ``action``."""
    expected = [str(i) for i in range(len(levels))]
    probs = raw.get("probabilities", {})
    if set(map(str, probs)) != set(expected):
        raise CompatError(
            f"score answer {question_id!r} probabilities cover {sorted(map(str, probs))!r}, "
            f"expected levels {expected!r}",
            field=f"answers.{question_id}.probabilities",
        )
    try:
        score = float(raw["score"])
    except (KeyError, TypeError, ValueError) as exc:
        raise CompatError(
            f"score answer {question_id!r} is missing a numeric 'score'",
            field=f"answers.{question_id}.score",
        ) from exc
    if not 0.0 <= score <= float(len(levels) - 1):
        raise CompatError(
            f"score answer {question_id!r} has score {score!r} outside [0, {len(levels) - 1}]",
            field=f"answers.{question_id}.score",
        )
    return ScoreAnswer(
        type="score",
        score=score,
        legend={str(i): level for i, level in enumerate(levels)},
        probabilities={
            str(i): _clamp01(
                probs[i] if i in probs else probs[str(i)],
                f"answers.{question_id}.probabilities.{i}",
            )
            for i in range(len(levels))
        },
        confidence=_clamp01(raw.get("confidence"), f"answers.{question_id}.confidence"),
    )

Inference

laya_serve.inference

Inference backend abstraction.

The HTTP layer depends only on the :class:Backend protocol, never on torch/laya directly, so the server (and its tests) import and run without model weights installed:

  • :class:FakeBackend — deterministic, weight-free answers. Uniform distributions for choice/score, 0.5 for noul. Used for tests and local API development.
  • :class:LayaBackend — wraps laya.Router. Import of laya (and therefore torch) happens lazily inside the constructor, so merely importing this module stays cheap.

Context budgets (Jev: 64k total, 32k state+longest-question) are enforced pre-inference from :meth:Backend.count, so oversize requests fail fast with 422 instead of being silently truncated downstream.

Backend

Bases: Protocol

Minimal interface the API layer needs from any inference backend.

Source code in src/laya_serve/inference.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
class Backend(Protocol):
    """Minimal interface the API layer needs from any inference backend."""

    serving_model: str
    # Token budgets enforced pre-inference (Jev: 64k total, 32k
    # state+longest-question). Backends that predate this interface simply
    # omit them and skip enforcement.
    max_total_tokens: int
    max_state_question_tokens: int

    def predict(self, state: Any, questions: dict[str, dict[str, Any]]) -> dict[str, Any]:
        """Return ``{"answers": {...}, "usage": {...}}`` with raw backend answers."""
        ...

    def count(self, state: Any, questions: dict[str, dict[str, Any]]) -> tuple[int, int]:
        """Return ``(total, state_plus_longest)`` token estimates for budgets."""
        ...

count(state, questions)

Return (total, state_plus_longest) token estimates for budgets.

Source code in src/laya_serve/inference.py
112
113
114
def count(self, state: Any, questions: dict[str, dict[str, Any]]) -> tuple[int, int]:
    """Return ``(total, state_plus_longest)`` token estimates for budgets."""
    ...

predict(state, questions)

Return {"answers": {...}, "usage": {...}} with raw backend answers.

Source code in src/laya_serve/inference.py
108
109
110
def predict(self, state: Any, questions: dict[str, dict[str, Any]]) -> dict[str, Any]:
    """Return ``{"answers": {...}, "usage": {...}}`` with raw backend answers."""
    ...

FakeBackend

Deterministic weight-free backend for tests and local development.

Source code in src/laya_serve/inference.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
class FakeBackend:
    """Deterministic weight-free backend for tests and local development."""

    max_total_tokens = JEV_MAX_TOTAL_TOKENS
    max_state_question_tokens = JEV_MAX_STATE_QUESTION_TOKENS

    def __init__(self, serving_model: str = "laya-english") -> None:
        self.serving_model = serving_model
        self.calls: list[dict[str, Any]] = []

    def count(self, state: Any, questions: dict[str, dict[str, Any]]) -> tuple[int, int]:
        return count_request(state, questions)

    def predict(self, state: Any, questions: dict[str, dict[str, Any]]) -> dict[str, Any]:
        self.calls.append({"state": state, "questions": questions})
        answers: dict[str, Any] = {}
        for qid, qdef in questions.items():
            qtype = qdef["type"]
            if qtype == "noul":
                answers[qid] = {"type": "noul", "noul": 0.5}
            elif qtype == "choice":
                options = list(qdef["criteria"])
                prob = 1.0 / len(options)
                answers[qid] = {
                    "type": "choice",
                    "choice": options[0],
                    "probabilities": {opt: prob for opt in options},
                    "confidence": 0.0 if len(options) > 1 else 1.0,
                }
            elif qtype == "score":
                levels = list(qdef["criteria"])
                prob = 1.0 / len(levels)
                answers[qid] = {
                    "type": "score",
                    "score": (len(levels) - 1) / 2.0,
                    "legend": {str(i): level for i, level in enumerate(levels)},
                    "probabilities": {str(i): prob for i in range(len(levels))},
                    "confidence": 0.0,
                }
            else:  # pragma: no cover - validated upstream
                raise ValueError(f"unknown question type {qtype!r}")
        return {"answers": answers, "usage": {"input_tokens": 0, "output_tokens": 0}}

LayaBackend

Production backend wrapping laya.Router (lazy import).

Source code in src/laya_serve/inference.py
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
class LayaBackend:
    """Production backend wrapping ``laya.Router`` (lazy import)."""

    max_total_tokens = JEV_MAX_TOTAL_TOKENS
    max_state_question_tokens = JEV_MAX_STATE_QUESTION_TOKENS

    def __init__(self, settings: Settings) -> None:
        try:
            from laya import Router
        except ImportError as exc:
            raise RuntimeError(
                "laya is not installed; install the 'inference' extra "
                "(pip install 'laya-serve[inference]') or use backend='fake'"
            ) from exc
        self.serving_model = settings.serving_model
        self._router = Router(
            device=settings.device,
            max_loaded=settings.max_loaded,
            preload=settings.preload,
        )

    def predict(self, state: Any, questions: dict[str, dict[str, Any]]) -> dict[str, Any]:
        try:
            result = self._router.predict(state, questions)
        except OverloadedError:
            raise
        except Exception as exc:
            if is_overload(exc):
                raise OverloadedError(f"backend overloaded: {exc}") from exc
            raise
        # Router adds a non-Jev ``routing`` key; compat shaping ignores it.
        return {
            "answers": result["answers"],
            "usage": result.get("usage", {"input_tokens": 0, "output_tokens": 0}),
        }

    def count(self, state: Any, questions: dict[str, dict[str, Any]]) -> tuple[int, int]:
        """Estimate request tokens with a resident checkpoint tokenizer if any.

        Falls back to the weight-free word count when no checkpoint is
        loaded yet (cold start) or tokenization fails. Counts are raw
        lengths without ``build_sequence`` truncation, so genuinely
        oversize states still trip the budgets instead of saturating.
        """
        tok = self._resident_tokenizer()
        if tok is None:
            return count_request(state, questions)
        try:
            state_n = len(tok(render_text(state), add_special_tokens=False)["input_ids"])
            per_question = [
                len(tok(render_question_text(q), add_special_tokens=False)["input_ids"])
                for q in questions.values()
            ]
        except Exception:
            return count_request(state, questions)
        longest = max(per_question, default=0)
        return state_n + sum(per_question), state_n + longest

    def _resident_tokenizer(self) -> Any | None:
        """Return a loaded checkpoint tokenizer, most-recently-used first."""
        try:
            order = list(getattr(self._router, "_order", []) or [])
            agents = getattr(self._router, "_agents", {}) or {}
        except Exception:
            return None
        for key in reversed(order):
            try:
                tok = getattr(agents.get(key), "tok", None)
            except Exception:
                continue
            if tok is not None:
                return tok
        return None

count(state, questions)

Estimate request tokens with a resident checkpoint tokenizer if any.

Falls back to the weight-free word count when no checkpoint is loaded yet (cold start) or tokenization fails. Counts are raw lengths without build_sequence truncation, so genuinely oversize states still trip the budgets instead of saturating.

Source code in src/laya_serve/inference.py
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
def count(self, state: Any, questions: dict[str, dict[str, Any]]) -> tuple[int, int]:
    """Estimate request tokens with a resident checkpoint tokenizer if any.

    Falls back to the weight-free word count when no checkpoint is
    loaded yet (cold start) or tokenization fails. Counts are raw
    lengths without ``build_sequence`` truncation, so genuinely
    oversize states still trip the budgets instead of saturating.
    """
    tok = self._resident_tokenizer()
    if tok is None:
        return count_request(state, questions)
    try:
        state_n = len(tok(render_text(state), add_special_tokens=False)["input_ids"])
        per_question = [
            len(tok(render_question_text(q), add_special_tokens=False)["input_ids"])
            for q in questions.values()
        ]
    except Exception:
        return count_request(state, questions)
    longest = max(per_question, default=0)
    return state_n + sum(per_question), state_n + longest

OverloadedError

Bases: Exception

Transient backend overload; handled as a Jev-shaped 529.

Backends raise this when inference could succeed on retry after a short delay (GPU OOM under burst load, evicted checkpoint reload, upstream timeout). Clients retry with backoff, honoring Retry-After.

Source code in src/laya_serve/inference.py
57
58
59
60
61
62
63
64
65
66
class OverloadedError(Exception):
    """Transient backend overload; handled as a Jev-shaped ``529``.

    Backends raise this when inference could succeed on retry after a
    short delay (GPU OOM under burst load, evicted checkpoint reload,
    upstream timeout). Clients retry with backoff, honoring
    ``Retry-After``.
    """

    pass

build_backend(settings)

Instantiate the backend selected by settings.backend.

Source code in src/laya_serve/inference.py
236
237
238
239
240
241
242
def build_backend(settings: Settings) -> Backend:
    """Instantiate the backend selected by ``settings.backend``."""
    if settings.backend == "fake":
        return FakeBackend(serving_model=settings.serving_model)
    if settings.backend == "laya":
        return LayaBackend(settings)
    raise ValueError(f"unknown backend {settings.backend!r}; expected 'fake' or 'laya'")

count_request(state, questions)

Weight-free (total, state+longest-question) word count of a request.

Source code in src/laya_serve/inference.py
49
50
51
52
53
54
def count_request(state: Any, questions: dict[str, dict[str, Any]]) -> tuple[int, int]:
    """Weight-free (total, state+longest-question) word count of a request."""
    state_n = len(render_text(state).split())
    per_question = [len(render_question_text(q).split()) for q in questions.values()]
    longest = max(per_question, default=0)
    return state_n + sum(per_question), state_n + longest

is_overload(exc)

Return whether exc looks like transient overload (retryable).

Source code in src/laya_serve/inference.py
92
93
94
95
def is_overload(exc: BaseException) -> bool:
    """Return whether ``exc`` looks like transient overload (retryable)."""
    haystack = f"{type(exc).__name__} {exc}".lower()
    return any(marker in haystack for marker in _OVERLOAD_MARKERS)

render_question_text(qdef)

Rendered size basis of one question: instructions + criteria descriptions.

Source code in src/laya_serve/inference.py
38
39
40
41
42
43
44
45
46
def render_question_text(qdef: dict[str, Any]) -> str:
    """Rendered size basis of one question: instructions + criteria descriptions."""
    parts = [render_text(qdef.get("instructions", ""))]
    criteria = qdef.get("criteria")
    if isinstance(criteria, dict):
        parts.extend(render_text(v) for v in criteria.values() if v is not None)
    elif isinstance(criteria, list):
        parts.extend(render_text(level) for level in criteria)
    return " ".join(part for part in parts if part)

render_text(value)

Render one value as text, mirroring laya.common.render_criterion.

Source code in src/laya_serve/inference.py
31
32
33
34
35
def render_text(value: Any) -> str:
    """Render one value as text, mirroring ``laya.common.render_criterion``."""
    if isinstance(value, str):
        return value
    return json.dumps(value, ensure_ascii=False, separators=(", ", ": "), default=str)

CLI

laya_serve.cli

CLI entry point: laya-serve.

main()

Serve the app with uvicorn (host/port via UVIcorn env or defaults).

Source code in src/laya_serve/cli.py
11
12
13
14
15
def main() -> None:
    """Serve the app with uvicorn (host/port via UVIcorn env or defaults)."""
    settings = Settings()
    app = create_app(settings)
    uvicorn.run(app, host="0.0.0.0", port=8000)