//! Builds the "tail" of the docker command — everything after the image //! name (entrypoint, model, args, auto-generated flags). use crate::config::{Node, Recipe}; use crate::engine_flags::{EngineFlagsCtx, build_engine_args}; /// The subset of [`DockerCommandCtx`] that `build_tail` needs. pub(crate) struct TailCtx<'a> { pub recipe: &'a Recipe, pub tp_size: u32, pub pp_size: u32, pub nnodes: u32, pub init_port: u16, pub master_ib_ip: &'a str, } /// Build the docker command tail — everything after the image name. pub fn build_tail(ctx: &TailCtx<'_>, node: &Node) -> Vec { let mut tail = Vec::new(); // Entrypoint — from the recipe (e.g. ["vllm", "serve"]), returned raw. // Callers shell-quote the assembled command (Docker host side) or pass // to `build_mod_script` (which quotes each word for the container `-c`). if !ctx.recipe.entrypoint.is_empty() { tail.extend(ctx.recipe.entrypoint.clone()); } // Shared engine args: model, recipe args, distributed flags, headless. let ectx = EngineFlagsCtx { recipe: ctx.recipe, tp_size: ctx.tp_size, pp_size: ctx.pp_size, nnodes: ctx.nnodes, init_port: ctx.init_port, master_ib_ip: ctx.master_ib_ip, }; tail.extend(build_engine_args(&ectx, node)); // Docker always binds --host 0.0.0.0 and --port. tail.push("--host".to_string()); tail.push("0.0.0.0".to_string()); tail.extend(["--port".into(), ctx.recipe.port.to_string()]); tail }