Skip to content

Resolve model package paths and path-valued session options through ONNX Runtime#2255

Draft
jambayk wants to merge 4 commits into
mainfrom
jambayk/schema
Draft

Resolve model package paths and path-valued session options through ONNX Runtime#2255
jambayk wants to merge 4 commits into
mainfrom
jambayk/schema

Conversation

@jambayk

@jambayk jambayk commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Builds on model package loading (#2227) so onnxruntime-genai resolves every path reference in a variant's genai_config.json through ONNX Runtime's model package resolver. A variant can reference its weights, an EP context file, and shared assets (such as tokenizer or processor config) by sha256: shared-asset URI or relative path, and ONNX Runtime owns shared-asset resolution and path confinement.

What changed

  • Delegate genai_config.json path resolution to ORT's ModelPackage_ResolveStringRef when the model is loaded from a package, so sha256: shared-asset references and relative paths resolve consistently with the package rules. Config::ResolvePath now rejects a sha256: reference when the model is a plain directory, with a clear error, instead of producing a bogus path.
  • Resolve path-valued session options against the package. The external initializers folder (session.model_external_initializers_file_folder_path) and the EP context file path (ep.context_file_path) declared in a variant's session_options are resolved before being applied, so a variant can point at weights or a context file stored in a shared asset. For models loaded from memory, the external initializers folder defaults to the config directory only when the config did not already set it.
  • Resolve the OrtModelPackageApi experimental functions self-contained in GetModelPackageApi(), so genai does not vendor ONNX Runtime's experimental C++ header.
  • Author packages with schema_version "1.0".

Dependencies

This requires building against an ONNX Runtime that includes:

Testing

unit_tests --gtest_filter='ModelPackage.*' (CPU, built against an ONNX Runtime with the dependencies above): 10 tests pass, covering variant selection, tokenizer resolution through a sha256: shared asset, external-initializers folder resolution through a shared asset, and rejection of sha256: references in a plain directory.

jambayk and others added 4 commits June 23, 2026 19:07
Model package path resolution is delegated to ORT's
ModelPackage_ResolveStringRef. Config gains a package_resolver that captures the
OrtModelPackageContext and routes path-shaped genai_config.json values through
it, so a sha256: tokenizer_dir resolves to a content-addressed shared asset
(honoring manifest overrides) and relative paths resolve against the variant
directory. OpenAndSelectVariant returns the context to keep it alive for the
config's lifetime.

Test fixtures declare a single inline component with variant directories at the
package root, and the end-to-end tokenizer test references its tokenizer through
a sha256: shared asset. The docs describe the inline-component layout and the
sha256: scheme.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ion 1.0

The Ort::Experimental typed getters for the OrtModelPackageApi functions are generated in
this header from the experimental .inc using OrtApi::GetExperimentalFunction, instead of
relying on ONNX Runtime's onnxruntime_experimental_cxx_api.h, which pulls in
onnxruntime_cxx_api.h that genai does not vendor.

Model package test fixtures author schema_version as the "1.0" major.minor string.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Route the external initializers folder and ep.context_file_path session options
through Config::ResolvePath when applying config entries, so a variant's
genai_config can reference weights or the EP context file by sha256: shared-asset
URI or relative path. For memory-loaded models, only default the external
initializers folder to the config directory when the config did not already set
it. ResolvePath now rejects sha256: references outside a package instead of
producing a bogus path. Add HasConfigEntry to the session-options wrapper and
tests covering external-data resolution and the sha256 rejection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the model-package loader so that all path references originating from a package variant’s genai_config.json (including sha256: shared-asset URIs and relative paths) are resolved via ONNX Runtime’s model package resolver, and additionally resolves path-valued session options before applying them to ORT.

Changes:

  • Delegate genai_config.json path resolution to ORT’s ModelPackage_ResolveStringRef when loading from a package, and reject sha256: references when loading from a flat directory.
  • Resolve path-valued session option entries (notably session.model_external_initializers_file_folder_path and ep.context_file_path) via Config::ResolvePath before applying them.
  • Update tests + docs for the inline-component package layout and sha256: shared assets.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/model_package_test.cpp Updates package fixture authoring and adds E2E tests for sha256: tokenizer + external initializer folder resolution.
src/models/onnxruntime_inline.h Adds HasConfigEntry wrapper and resolves model package experimental function pointers by name (incl. ResolveStringRef).
src/models/onnxruntime_api.h Exposes HasConfigEntry and extends the model package API wrapper with ModelPackage_ResolveStringRef.
src/models/model.cpp Resolves path-valued session options and adjusts external-initializers defaulting for in-memory loads; wires package resolver into Config.
src/models/model_package.h Keeps the package context alive in the load result for deferred path resolution.
src/models/model_package.cpp Stores the opened package context in the load result.
src/config.h Adds package_resolver callback used when loading from a package.
src/config.cpp Reworks ResolvePath to delegate to ORT when in a package; rejects sha256: in flat directories.
docs/model_package.md Updates documentation to describe inline components and sha256: shared assets.
Comments suppressed due to low confidence (1)

src/models/onnxruntime_inline.h:1575

  • Ort::GetModelPackageApi() only checks CreateModelPackageContext for availability. If an ONNX Runtime build has the model package API but lacks the newer ModelPackage_ResolveStringRef entry, later calls through ResolveStringRef() will dereference a null function pointer and crash. Guard for ModelPackage_ResolveStringRef (and ideally any other required entries) and fail with a clear error early.
  if (fns.CreateModelPackageContext == nullptr) {
    throw std::runtime_error(
        "Model package API is not available in this ONNX Runtime build. "
        "Model packages require ONNX Runtime with the OrtModelPackageApi experimental functions.");
  }

Comment on lines +107 to +123
fs_std::path ExportModelWithExternalData(const fs_std::path& src_onnx, const fs_std::path& out_dir) {
// The low-level ORT wrappers below run in this test binary, which has its own copy of the
// Ort::api pointer (the genai .so initializes its own). Initialize ours before using them.
Ort::InitApi();
fs_std::create_directories(out_dir);
const auto model_path = out_dir / "model.onnx";
auto session_options = OrtSessionOptions::Create();
session_options->SetGraphOptimizationLevel(ORT_DISABLE_ALL);
session_options->SetOptimizedModelFilePath(model_path.c_str());
session_options->AddConfigEntry("session.optimized_model_external_initializers_file_name",
"model.onnx.data");
session_options->AddConfigEntry("session.optimized_model_external_initializers_min_size_in_bytes",
"0");
// Creating the session writes the optimized model + external data as a side effect.
auto session = OrtSession::Create(Generators::GetOrtEnv(), src_onnx.c_str(), session_options.get());
return model_path;
}
Comment thread src/models/model.cpp
const char* values[] = {"false", "true"};

// Resolve tokenizer_dir (may be empty, relative, absolute, or "package:"-scheme).
// Resolve tokenizer_dir (may be empty, relative, or a "sha256:" shared-asset reference).
Comment thread docs/model_package.md
```jsonc
// manifest.json
{
"schema_version": 1,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants