#!/bin/bash
# set -eo pipefail
# BI-V100 engine patches for Qwen3.6-35B-A3B (Qwen3_5 architecture)
#
# All modifications are FULL FILE REPLACEMENTS — no AST patch scripts.
# Each file was read in full from the base image vllm source, modified
# with the necessary fixes, and placed here as a complete copy.
#
# Base image: git.modelhub.org.cn:9443/enginex-iluvatar/bi100-3.2.3-x86-ubuntu20.04-py3.10-poc-llm-infer:v1.2.3
# vllm install path: /usr/local/corex/lib/python3/dist-packages/vllm/

# CRITICAL: cd into this script's directory so all ./relative paths work
# regardless of WORKDIR in Dockerfile or caller's cwd.
cd "$(dirname "$0")"
echo "[patch_ops] working directory: $(pwd)"

VLLM=/usr/local/corex/lib/python3/dist-packages/vllm
VLLM64=/usr/local/corex/lib64/python3/dist-packages/vllm

# Deploy to ALL existing vllm paths — Python may load from either one
# depending on PYTHONPATH ordering and namespace package resolution.
TARGETS=()
if [ -d "$VLLM" ]; then
    TARGETS+=("$VLLM")
fi
if [ -d "$VLLM64" ]; then
    TARGETS+=("$VLLM64")
fi

if [ ${#TARGETS[@]} -eq 0 ]; then
    echo "[patch_ops] ERROR: vllm not found at lib or lib64 path"
    exit 1
fi

echo "[patch_ops] vllm paths found: ${TARGETS[*]}"

# Helper: copy file to all target vllm roots
deploy() {
    local src="$1"
    local rel_dst="$2"  # relative path within vllm, e.g. "attention/ops/paged_attn.py"
    for V in "${TARGETS[@]}"; do
        local dst="$V/$rel_dst"
        mkdir -p "$(dirname "$dst")"
        cp "$src" "$dst"
    done
}

# --- _custom_ops.py: SMEM 48KB fix + hardware ops bindings -------------------
# Base image returns 32KB (32768) for get_max_shared_memory_per_block, but
# BI-V100 actually has 48KB (49152) confirmed via ixsmi. This limits Triton
# tile sizes and ixformer internal allocations if not corrected.
# CCCL GridEvenShare test (catch2_test_grid_even_share.cu) validates that
# work distribution depends on correct hardware parameters — wrong SMEM
# means wrong tile_size means wrong grid_size.
# FULL FILE REPLACEMENT.
deploy ./_custom_ops.py "_custom_ops.py"
echo "[patch_ops] _custom_ops.py → / (SMEM 32KB→48KB fix)"

# --- paged_attn.py: pure-PyTorch attention fallback --------------------------
deploy ./paged_attn.py "attention/ops/paged_attn.py"
echo "[patch_ops] paged_attn.py → attention/ops/"

# --- prefix_prefill.py: Triton-free prefix attention -------------------------
deploy ./prefix_prefill.py "attention/ops/prefix_prefill.py"
echo "[patch_ops] prefix_prefill.py → attention/ops/"

# --- model_runner.py: prefix_cache_hit fix -----------------------------------
deploy ./model_runner.py "worker/model_runner.py"
echo "[patch_ops] model_runner.py → worker/"

# --- xformers.py: head_dim>128 fallback + Q-tiling --------------------------
deploy ./xformers.py "attention/backends/xformers.py"
echo "[patch_ops] xformers.py → attention/backends/"

# --- arg_utils.py: disable auto chunked-prefill for 32K+ --------------------
deploy ./arg_utils.py "engine/arg_utils.py"
echo "[patch_ops] arg_utils.py → engine/"

# --- logits_processor.py: seq_groups=None guard ------------------------------
deploy ./logits_processor.py "model_executor/layers/logits_processor.py"
echo "[patch_ops] logits_processor.py → model_executor/layers/"

# --- sampler.py: CCCL-ported top-k fast path for sampling --------------------
deploy ./sampler.py "model_executor/layers/sampler.py"
echo "[patch_ops] sampler.py → model_executor/layers/"

# --- transformers: Qwen3_5 tokenizer / model files --------------------------
# NOTE: patch_transformers_qwen3_5.py is the ONLY remaining patch script.
# It modifies pip-installed transformers' configuration_auto.py and __init__.py
# to register qwen3_5/qwen3_5_moe. These files come from pip (version-specific)
# so we can't pre-copy them — the patch script inserts lines after known anchors.
# pip install transformers==4.55.3 -i https://pypi.tuna.tsinghua.edu.cn/simple 2>/dev/null || \
# pip install transformers==4.55.3 2>/dev/null || \
echo "[patch_ops] WARNING: pip install transformers failed, using pre-installed version"
cp -r ./qwen3_5 /usr/local/lib/python3.10/site-packages/transformers/models/
cp -r ./qwen3_5_moe /usr/local/lib/python3.10/site-packages/transformers/models/
python3 ./patch_transformers_qwen3_5.py
echo "[patch_ops] transformers Qwen3_5 models installed"

# --- vllm model: Qwen3.6 (Qwen3_5 arch) ------------------------------------
for V in "${TARGETS[@]}"; do
    cp ./mamba_cache.py "$V/model_executor/models/"
done
deploy ./qwen3_5.py "model_executor/models/qwen3_5.py"
deploy ./registry.py "model_executor/models/registry.py"
echo "[patch_ops] qwen3_5.py + registry.py deployed"

# --- paged_attention_v2_pytorch.py: PyTorch V2 attention fallback ------------
for V in "${TARGETS[@]}"; do
    cp ./paged_attention_v2_pytorch.py "$V/paged_attention_v2_pytorch.py"
done
cp ./paged_attention_v2_pytorch.py /workspace/paged_attention_v2_pytorch.py
echo "[patch_ops] paged_attention_v2_pytorch.py → all paths + /workspace/"

# --- sequence.py: fix completion_tokens inflation ----------------------------
deploy ./sequence.py "sequence.py"
echo "[patch_ops] sequence.py → /"

# --- scheduler.py: record num_cached_tokens ---------------------------------
deploy ./scheduler.py "core/scheduler.py"
echo "[patch_ops] scheduler.py → core/"

# --- tool parser: Qwen3 XML tool call format --------------------------------
for V in "${TARGETS[@]}"; do
    cp ./qwen3coder_tool_parser.py "$V/entrypoints/openai/tool_parsers/"
    cp ./tool_parsers_init.py "$V/entrypoints/openai/tool_parsers/__init__.py"
done
echo "[patch_ops] qwen3_coder tool parser deployed"

# --- reasoning parser: Qwen3 <think>...</think> split -----------------------
for V in "${TARGETS[@]}"; do
    cp -r ./reasoning "$V/"
    cp ./protocol.py "$V/entrypoints/openai/protocol.py"
    cp ./cli_args.py "$V/entrypoints/openai/cli_args.py"
    cp ./serving_chat.py "$V/entrypoints/openai/serving_chat.py"
    cp ./api_server.py "$V/entrypoints/openai/api_server.py"
    cp ./chat_utils.py "$V/entrypoints/chat_utils.py"
done
echo "[patch_ops] reasoning parser + serving files installed"

echo "[patch_ops] DONE — all patches applied via full file replacement"
