feat(abi): embeddings/pooling through the ONE surface — LlamaModel arch, PoolingRunner in the engine step, vllm_embed (ABI v15), live /v1/embeddings - #137
Conversation
…oling arch, PoolingRunner in the engine step, vllm_embed (ABI v15), live /v1/embeddings ARCH-ONE-SURFACE fold ROW 6 (task #285, branch row/EMBEDDINGS-ONE-SURFACE, PR #137). The engine-side pooler (ENG-POOLER-SEQ ops + ENG-POOLING-RUNNER PoolingRunner) is now INVOKED LIVE through one path: vllm_engine_load on a pooling checkpoint -> LLMEngine::embed -> scheduler -> GPUModelRunner::pool_tokens -> pooled vector, driven identically by vllm_embed (ABI v15) and the live task-conditional /v1/embeddings. W1 registry+runner: NEW arch LlamaModel (llama_embedding_registry.cpp, is_pooling_model=true) — the mirror of _EMBEDDING_MODELS "LlamaModel": ("llama", "LlamaForCausalLM") (registry.py:230) + as_embedding_model (adapters.py:230): the SHARED dense backbone to the post-final-norm hidden with NO lm_head (Qwen3DenseModel::ForwardHidden, additive tail; text callers byte-identical); loader accepts both name layouts (adapters.py:178-181) and never loads lm_head. The runner builds a PoolingRunner iff the registration declares pooling (model_runner.py:368-369) and sample_tokens routes to pool_tokens() (model_runner.py:1586-1607); validity == the discard predicate (pooling_runner.py:40-41); scheduler pooling stop at the marked DEFERRED site (scheduler.py:1718-1721); pooling_output out through EngineCoreOutput/RequestOutput; async scheduling OFF for pooling models (config/vllm.py:1068-1073 — the landed ResolveAsyncScheduling arm now WIRED). Every hook task-gated on is_pooling_model / pooling_params: default nullopt/false = byte-identical text path (engine suites re-run green). W2 ABI: vllm_embed + vllm_embedding_result_free, VLLM_ABI_VERSION 14 -> 15, floor pin >= 15; strict-C references; dlopen symbols; refuse-by-task BOTH directions; FIXED en route: v13's vllm_complete_tokens shipped without the v11 task guard (null-deref on a transcription handle). W3 server: handle_embeddings (OpenAI shape, embed/protocol.py:34, 173-185) registered ONLY when an embedder is attached; server main dispatches pooling archs to a serving-less embedding server; socket-level 404 pins BOTH directions. W4 guard/records: abi-capability-allowlist embeddings row REMOVED (1 left: mm-input); FEATURES row -> reachable; ARCH_TOKEN_RE widened to bare *Model; the routing checker gains the POOLING classification; runnable-baseline re-pinned; SERVE-POOLING-ENDPOINTS and MODEL-EMBED-llama-llama-for-causal-lm rows ACTIVE; STATUS/BENCHMARKS/NOW/state updated. Correctness anchor: the pooling lane's cosine gate re-anchored THROUGH the registry/runner path on the COMMITTED deterministic fixture (scripts/mm/llama_embed_fixture_gen.py): test_llama_embedding_fold 4/4-231 — direct registry path == f64 LAST+normalize reference, FULL-ENGINE path == direct path IDENTICAL vectors, chunked-prefill is_valid arm — plus test_capi 48/48-462 (real fixture-checkpoint load through the public ABI), test_dlopen 30/30, server suite 50/50, registry 24/24-820. 9 mutation kills (floor pin, refusals both directions, route gating both ways, engine-step invocation, scheduler stop, registry info pin, async-off wire). Residual: REAL embedding checkpoint (e5-mistral class) + the LLM(task="embed") oracle cosine — no cosine-vs-oracle number fabricated. FOLLOWING_AGENTS_PROTOCOL Assisted-by: Claude Code:claude-fable-5 [ClaudeCode]
fde0a29 to
e4c29b3
Compare
|
Implementation complete at e4c29b3 (rebased onto main e484a63; keyed records re-applied on main wholesale). Gates (CPU): fold gate Mutation kills (each RED then reverted, 9): ABI floor 15→14 (floor pin RED) · embed-on-text refusal deleted (capi RED ×3) · generation-on-pooling refusal deleted (refusal case hangs → SIGTERM FAILURE) · Allowlist diff: Residuals (honest): REAL embedding checkpoint (e5-mistral class) + Note for the reviewer: the brief's premise that the pooling lane's gate ran "vs recorded oracle fixtures" was inaccurate — the existing gate is structural (double-precision reference; the |
…ch, PoolingRunner live, vllm_embed at ABI v15, /v1/embeddings (#137) ONE-SURFACE fold ROW 6, the last capability fold before mm-input. The pooling machinery that existed engine-side but was never invoked live now runs through every surface: LlamaModel registered is_pooling_model=true (the _EMBEDDING_MODELS registry.py:230 + as_embedding_model adapters.py:230 mirror; bare-prefix no-lm_head loader; Qwen3DenseModel::ForwardHidden additive tail), PoolingRunner built iff pooling model and invoked task-gated in sample_tokens -> pool_tokens (model_runner.py:1586-1607 mirror), scheduler pooling stop at the previously-DEFERRED site, async scheduling off for pooling (config/vllm.py:1068-1073). vllm_embed + vllm_embedding_result_free at VLLM_ABI_VERSION 14->15 floor-pinned; task-conditional /v1/embeddings (OpenAI shape) with both-direction socket-level 404 pins; capability allowlist down to exactly ONE row (mm-input). LAST-pool + normalize matches upstream defaults verbatim. Adjacent fix: v13's vllm_complete_tokens shipped without the task guard - a confirmed pre-existing null-deref/hang on transcription handles, now guarded and pinned. Review: fresh mutation review MERGE-CLEAN - every engine-step/scheduler touch verified gated with the text path byte-identical (ungated mutations red the text suites), both refusal guards load-bearing (removal reproduces real HANGS), the fold gate's engine-vs-direct arms independently killable, all upstream cites verbatim, fixture regeneration byte-stable. One minor observation recorded for the next row: the routing checker's NONE bucket silently absorbs pooling registrations (its CI-bound mutation suite holds the pin). Operator: fold/capi/dlopen/server/scheduler/llm_engine 6/6 SUCCESS on the merged tree; nine record gates green; FEATURES conflict composed (embeddings row from this PR, ROCm row from main's newer community-verified state). FOLLOWING_AGENTS_PROTOCOL Assisted-by: Claude Code:claude-fable-5 [ClaudeCode]
|
Landed on main as 57ed063 (mudler-authored squash, lease-guarded verified push). Fresh mutation review MERGE-CLEAN: every engine-step/scheduler pooling branch verified gated (text path byte-identical; ungated mutations red the text suites), both refusal guards load-bearing (removal reproduces real hangs), fold-gate arms independently killable, upstream cites verbatim, fixture byte-stable. Operator gates on the merged tree: six suites 6/6 SUCCESS, nine record gates green, FEATURES conflict composed with main's newer ROCm state. Embeddings are now embedder-reachable end-to-end: LlamaModel registry arch, live PoolingRunner, vllm_embed at ABI v15, /v1/embeddings. The capability tracker is at ONE remaining row (mm-input). The adjacent v13 vllm_complete_tokens guard fix rode along (confirmed pre-existing hang). Residuals as recorded: real-checkpoint cosine oracle, classify/score heads, matryoshka/base64 inputs, batched vllm_embed. |
Record the merged Gemma-4 MoE path as known merged-GEMM drift and close the stale embeddings claim after PR mudler#137 landed. FOLLOWING_AGENTS_PROTOCOL Assisted-by: Codex:gpt-5.6-sol [Codex]
Record the merged Gemma-4 MoE path as known merged-GEMM drift and close the stale embeddings claim after PR mudler#137 landed. FOLLOWING_AGENTS_PROTOCOL Assisted-by: Codex:gpt-5.6-sol [Codex]
ONE-SURFACE fold ROW 6 (task #285, row
ARCH-ONE-SURFACEleaf).The engine-side pooler (ENG-POOLER-SEQ / ENG-POOLING-RUNNER) exists but is never invoked live. This row folds it onto the one surface:
LlamaModel(upstream_EMBEDDING_MODELS, registry.py:230,as_embedding_modeladapters.py:230) withis_pooling_model=true; the engine step routes pooling-model batches through the landedPoolingRunnerinstead of the sampler (model_runner.py:368-369, 1586-1607; scheduler.py:1718-1721). Refuse-by-task both directions.vllm_embed+vllm_embedding_result(_free), VLLM_ABI_VERSION 14→15, floor pin advanced, strict-C references./v1/embeddings(OpenAI shape), task-conditional registration, socket-level 404 pins both directions.Correctness anchor: the pooling lane's cosine gate extended with a registry-path arm — the engine-path vectors must be IDENTICAL to the direct PoolingRunner path and match the double-precision LAST+normalize reference, on a committed tiny synthetic
LlamaModelfixture (the #121 precedent). Real-checkpoint re-verification is a named residual.Spec:
.agents/specs/embeddings-one-surface.md🤖 Generated with Claude Code
https://claude.ai/code/session_014fZAcg1WcU8V629k6HWKys