ask a pod for an engine its image actually carries (v0.4.99)

`pod_ocr_engine` rewrote EVERY whole-request OCR forward to docTR. The premise
was that a pod image cannot carry a VLM's model server, which was true of
`coderai-vllm` and never true of `coderai-vllm-ocr`: that image carries surya,
the rasteriser and its own vLLM -- it IS the pod-side pipeline -- and it
carries no docTR at all, which is why its pods launch with
CODERAI_OCR_FALLBACK_ENGINES=off.

So the rewrite asked a pipeline pod for the one engine it cannot possibly have,
and the pod answered "OCR engine 'doctr' is not enabled". The question cannot
be asked without the image, and the gateway was not passing one.

Found by sending a page through a pod, not by reading the code: the id
resolved, the pool provisioned, the pod booted and went ready, and the request
still came back 400 naming an engine nobody had asked for.

A named configuration (ocr.engine_configs) also resolves to its base engine
here. The ids are an orchestrator-side naming layer and a pod is a
pre-configured instance of one -- its env already carries the overrides -- so
telling it the id names an engine it has never heard of.

Omitting the image keeps the old answer, so callers that cannot know it are
unchanged.
Co-Authored-By: 's avatarClaude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S8LAP3ueNzQJtwzhgVbq66
parent 1ef6b8f6
......@@ -16,7 +16,7 @@
# Canonical product version for CoderAI — single source of truth. Both the API
# metadata and the admin web UI read from here.
__version__ = "0.4.98"
__version__ = "0.4.99"
__tagline__ = "Complete orchestration, distribution and escalation of remotizable advanced inference."
# Configure the CUDA caching allocator BEFORE torch is imported anywhere.
......
......@@ -747,11 +747,21 @@ def resolve_target(path: str, method: str, query: str, body: bytes,
resolve_model_source, pod_ocr_engine)
target = Target(pool=get_model_pod_pool(model, entry, block),
reason=f"model {model!r} on its own RunPod pod")
mcfg = parse_model_runpod(block)
if cap == "ocr":
served = pod_ocr_engine(model)
# WITH THE IMAGE, because what a pod can serve depends on it: a
# pipeline image (coderai-vllm-ocr) serves surya/chandra/olmOCR
# itself and carries no docTR, while a plain one is the other way
# round. Asked without it, this rewrote every OCR forward to docTR
# and a pipeline pod answered "docTR is not enabled".
from codai.api.runpod_worker import pod_image_for_entry
try:
_img = pod_image_for_entry(entry, mcfg)
except Exception:
_img = str(block.get("image") or "")
served = pod_ocr_engine(model, _img)
if served and served != model.strip().lower():
target.rewrite_field = (_MODEL_FIELD.get(path, "model"), served)
mcfg = parse_model_runpod(block)
kind, _ = resolve_model_source(entry, mcfg)
if kind == "upload":
target.upload_entry = entry
......
......@@ -1204,17 +1204,44 @@ def volume_env(mount: str) -> dict:
}
def pod_ocr_engine(requested: str) -> str:
def pod_ocr_engine(requested: str, image: str = "") -> str:
"""The OCR engine a pod will actually serve for a request naming ``requested``.
Mirrors the env a pod is launched with: the VLM engines (surya, olmOCR,
chandra) need a model server the image does not carry, so a pod serves docTR
for them. The gateway uses this to rewrite the request's own `engine` field,
because the pod honours what the request asks for over its configured default.
Mirrors the env a pod is launched with. The gateway uses it to rewrite the
request's own `engine` field, because the pod honours what the request asks
for over its configured default.
TWO KINDS OF POD IMAGE, and this used to answer for only one. On a plain
`coderai-vllm` pod the VLM engines (surya, olmOCR, chandra) need a model
server the image does not carry, so such a pod serves docTR for them --
which is what the whole function said. But a `coderai-vllm-ocr` pod carries
surya, the rasteriser and its own vLLM: it serves those engines itself,
which is the entire pod-side pipeline. Worse, that image carries **no
docTR** (`CODERAI_OCR_FALLBACK_ENGINES=off` is set for exactly that
reason), so rewriting to docTR there asks a pod for the one engine it
cannot possibly have, and the answer is "OCR engine 'doctr' is not
enabled". Every whole-request `/v1/ocr` forward to a pipeline pod failed
that way.
A NAMED CONFIGURATION resolves to its base engine. `ocr.engine_configs` is
an orchestrator-side naming layer: the pod is a pre-configured instance of
one configuration (its env already carries the overrides), so telling it
the id would name an engine it has never heard of.
"""
r = (requested or "").strip().lower()
try:
from codai.ocr import engine_configs
from codai.admin.routes import config_manager
ocfg = getattr(getattr(config_manager, "config", None), "ocr", None)
if ocfg is not None:
_cid, _base, _ov = engine_configs.resolve(ocfg, r)
if _ov or _base != r:
r = _base
except Exception:
pass
if r in ("surya", "olmocr", "chandra"):
return "doctr"
# The pipeline image serves these itself; anything else cannot.
return r if image_runs_ocr_pipeline(image) else "doctr"
return r if r in ("paddle", "doctr") else "doctr"
......
......@@ -287,3 +287,61 @@ def test_the_layout_switches_travel_to_a_pod_as_booleans():
blk = blk[:blk.index("CODERAI_VLLM_RETURN_TOKEN_IDS")]
assert "CODERAI_OCR_SURYA_LAYOUT" in blk
assert "CODERAI_OCR_SURYA_TABLE_REC" in blk
# --------------------------------------------------------------------------- #
# what a POD is told the engine is
# --------------------------------------------------------------------------- #
PIPE_IMG = "ghcr.io/nextime/coderai-vllm-ocr:0.4.98"
PLAIN_IMG = "ghcr.io/nextime/coderai-vllm:latest"
def test_a_pipeline_pod_is_asked_for_the_engine_it_actually_carries():
"""Found by running a page through it, not by reading the code.
`pod_ocr_engine` rewrote EVERY OCR forward to docTR, on the premise that a
pod image cannot carry a VLM's model server. `coderai-vllm-ocr` does carry
one -- that is the whole pod-side pipeline -- and carries no docTR at all,
so the rewrite asked a pipeline pod for the one engine it cannot have and
the pod answered "OCR engine 'doctr' is not enabled". Every whole-request
/v1/ocr forward to a pipeline pod failed that way.
"""
from codai.api.runpod_worker import pod_ocr_engine
for eng in ("surya", "chandra", "olmocr"):
assert pod_ocr_engine(eng, PIPE_IMG) == eng
def test_a_plain_pod_still_falls_back_to_doctr():
"""The original reasoning, still right for an image with no model server."""
from codai.api.runpod_worker import pod_ocr_engine
for eng in ("surya", "chandra", "olmocr"):
assert pod_ocr_engine(eng, PLAIN_IMG) == "doctr"
def test_the_detector_engines_pass_through_either_way():
from codai.api.runpod_worker import pod_ocr_engine
for img in (PIPE_IMG, PLAIN_IMG):
assert pod_ocr_engine("paddle", img) == "paddle"
assert pod_ocr_engine("doctr", img) == "doctr"
def test_an_unknown_engine_is_still_doctr():
from codai.api.runpod_worker import pod_ocr_engine
assert pod_ocr_engine("nonsense", PIPE_IMG) == "doctr"
def test_omitting_the_image_keeps_the_old_answer():
"""Callers that cannot know the image must not change behaviour."""
from codai.api.runpod_worker import pod_ocr_engine
assert pod_ocr_engine("surya") == "doctr"
def test_the_gateway_asks_with_the_image():
"""A pod's capability depends on its image, so the question cannot be asked
without one — that omission is what sent every OCR forward to docTR."""
src = open("codai/api/remote_gateway.py").read()
assert "pod_ocr_engine(model, _img)" in src
head = src.index("if cap == \"ocr\":")
body = src[head:head + 900]
assert "pod_image_for_entry" in body
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment