@@ -45,6 +45,11 @@ void ModelCompilationOptions::SetInputModelFromBuffer(const void* input_model_da
4545 input_model_data_size_ = input_model_data_size;
4646}
4747
48+ void ModelCompilationOptions::SetInputModel (const OrtModel* model) {
49+ ResetInputModelSettings ();
50+ input_model_ = model;
51+ }
52+
4853Status ModelCompilationOptions::SetOutputModelPath (const std::filesystem::path& output_model_path) {
4954 ConfigOptions& config_options = session_options_.value .config_options ;
5055 epctx::ModelGenOptions& ep_context_gen_options = session_options_.value .ep_context_gen_options ;
@@ -186,10 +191,19 @@ size_t ModelCompilationOptions::GetInputModelDataSize() const {
186191 return input_model_data_size_;
187192}
188193
194+ bool ModelCompilationOptions::InputModelComesFromOrtModel () const {
195+ return input_model_ != nullptr ;
196+ }
197+
198+ const OrtModel* ModelCompilationOptions::GetInputModel () const {
199+ return input_model_;
200+ }
201+
189202void ModelCompilationOptions::ResetInputModelSettings () {
190203 input_model_path_.clear ();
191204 input_model_data_ = nullptr ;
192205 input_model_data_size_ = 0 ;
206+ input_model_ = nullptr ;
193207}
194208
195209Status ModelCompilationOptions::SetGraphOptimizationLevel (GraphOptimizationLevel graph_optimization_level) {
@@ -229,16 +243,21 @@ Status ModelCompilationOptions::Check() const {
229243 // Check input model settings.
230244 const bool input_from_file = !input_model_path_.empty ();
231245 const bool input_from_memory = input_model_data_ != nullptr ;
246+ const bool input_from_model = input_model_ != nullptr ;
247+
248+ int input_source_count = (input_from_file ? 1 : 0 ) +
249+ (input_from_memory ? 1 : 0 ) +
250+ (input_from_model ? 1 : 0 );
232251
233- if (!input_from_file && !input_from_memory ) {
252+ if (input_source_count == 0 ) {
234253 return ORT_MAKE_STATUS (ONNXRUNTIME, INVALID_ARGUMENT,
235- " Input model to compile must be loaded from either a file or a memory buffer" );
254+ " Input model to compile must be specified via file path, memory buffer, or OrtModel " );
236255 }
237256
238- if (input_from_file && input_from_memory ) {
257+ if (input_source_count > 1 ) {
239258 return ORT_MAKE_STATUS (ONNXRUNTIME, INVALID_ARGUMENT,
240- " Input model to compile must be loaded from either a file or a memory buffer, " ,
241- " but not both. " );
259+ " Input model to compile must be specified via exactly one of: " ,
260+ " file path, memory buffer, or OrtModel " );
242261 }
243262
244263 if (input_from_file && !std::filesystem::exists (input_model_path_)) {
@@ -249,12 +268,59 @@ Status ModelCompilationOptions::Check() const {
249268 return ORT_MAKE_STATUS (ONNXRUNTIME, INVALID_ARGUMENT, " Buffer for input model data has size 0" );
250269 }
251270
271+ // Validate OrtModel input
272+ if (input_from_model) {
273+ if (input_model_->graph == nullptr ) {
274+ return ORT_MAKE_STATUS (ONNXRUNTIME, INVALID_ARGUMENT,
275+ " OrtModel has no graph. Call AddGraphToModel before compilation." );
276+ }
277+
278+ if (input_model_->graph ->GetNumInputs () == 0 || input_model_->graph ->GetNumOutputs () == 0 ) {
279+ return ORT_MAKE_STATUS (ONNXRUNTIME, INVALID_ARGUMENT,
280+ " OrtModel graph must have at least one input and one output defined." );
281+ }
282+
283+ if (input_model_->domain_to_version .empty ()) {
284+ return ORT_MAKE_STATUS (ONNXRUNTIME, INVALID_ARGUMENT,
285+ " OrtModel must specify at least one opset domain/version." );
286+ }
287+
288+ // Note: Additional validation (node connections, schema) happens during
289+ // Model::LoadFromModelEditorApiModel -> Graph::Resolve()
290+ }
291+
252292 // Check output model settings.
253293 const epctx::ModelGenOptions& ep_context_gen_options = session_options_.value .ep_context_gen_options ;
254294 bool has_no_output_model_location = std::holds_alternative<std::monostate>(
255295 ep_context_gen_options.output_model_location );
256296
257- if (has_no_output_model_location && input_from_file) {
297+ // Determine if we can derive an output path from the input
298+ bool can_derive_output_path = input_from_file;
299+ bool model_has_path = false ;
300+
301+ // For OrtModel input, check if model_path is set in the graph using the virtual GetModelPath() method
302+ // (avoids dynamic_cast which requires RTTI)
303+ if (input_from_model && input_model_->graph ) {
304+ const ORTCHAR_T* model_path_cstr = input_model_->graph ->GetModelPath ();
305+ if (model_path_cstr && model_path_cstr[0 ] != ORT_TSTR (' \0 ' )) {
306+ can_derive_output_path = true ;
307+ model_has_path = true ;
308+ }
309+ }
310+
311+ // Fast-fail: If OrtModel has no model_path and user hasn't specified output location or embed mode,
312+ // EPs that need to write context binaries will fail later. Fail early with a clear error.
313+ if (input_from_model && !model_has_path && has_no_output_model_location &&
314+ !ep_context_gen_options.embed_ep_context_in_model ) {
315+ return ORT_MAKE_STATUS (ONNXRUNTIME, INVALID_ARGUMENT,
316+ " OrtModel has no model_path set and no output location was specified. "
317+ " Please either: (1) set the model_path on the OrtGraph before adding to OrtModel, "
318+ " (2) call SetOutputModelPath/SetOutputModelBuffer to specify an output location, "
319+ " (3) call SetEpContextEmbedMode(true) to embed EP context in the model, or "
320+ " (4) call SetEpContextBinaryInformation to specify the binary output directory." );
321+ }
322+
323+ if (has_no_output_model_location && can_derive_output_path) {
258324 // User did not specify an output file, an output buffer, or an output write function. We default to generating an
259325 // output file with a name based on the input file name, so do not return an error.
260326 return Status::OK ();
0 commit comments