Skip to content

Commit 6f283a3

Browse files
jambaykCopilotjambayk
authored andcommitted
Expand model package with authoring tools and schema versioning (#28989)
### Description Builds out the standalone `model_package/` C library so a single library covers the full lifecycle of an ONNX Runtime model package: inspection, authoring, content-addressed shared assets, commit, prune, and validation. The library remains free of any dependency on ONNX Runtime itself. **Public C API (`model_package/include/model_package.h`)** - Lifecycle: `ModelPackage_Open` / `ModelPackage_New` / `ModelPackage_Close`, with `ModelPackageOpenOptions` controlling external-path access, symlink following, and strict unknown-field handling. - Inspection: a POD `ModelPackageInfo` tree (`ModelPackage_Info`) plus by-name lookups for components, variants, and per-namespace `executor_info` entries, and round-trip JSON getters that preserve fields unknown to the current build. - Path resolution: `ModelPackage_ResolveStringRef` implements the package's resolution rules — relative paths anchored at a base directory, `sha256:<hex>[/sub/path]` for shared-asset content, and portable vs installed confinement (absolute paths and `..` segments only allowed under `layout: "installed"`). - Shared assets: SHA-256 directory hashing, `ModelPackage_AddSharedAsset` (with reproducible-build URI check and an optional `copy_in` staging mode), `ModelPackage_RemoveSharedAsset`, and `ModelPackage_ResolveAssetUri`. Assets under `<package_root>/shared_assets/` are auto-discovered at `Open`. - Authoring: inline/external component setters, variant upsert/remove, per-namespace executor_info setters (inline and external), and package-level metadata / layout / `additional_metadata` setters. Mutations invalidate cached pointers in the mutated scope and its descendants. - Commit / prune / validate: `ModelPackage_Commit` writes the in-memory model to disk either in place or to a fresh `dest_root` ("save as"), with `PRESERVE` or `DENSE` write modes; `ModelPackage_Prune` reclaims unreferenced files under `shared_assets/` and tracked orphan variant/component directories left behind by removals; and `ModelPackage_Validate` runs schema, path-reachability, asset-rehash, and unknown-field checks and returns a JSON report. - Errors: opaque `ModelPackageStatus*` with a stable additive `ModelPackageErrorCode` enum (IO, schema, version, path confinement, asset missing, asset hash mismatch, not found, invalid arg, state). **Internal layout** The implementation is split into focused translation units: `manifest_parser`, `model_package_impl`, `authoring`, `commit_prune_validate`, `path_resolver`, `asset_hasher`, and an in-tree `sha256`. Shared error plumbing lives in `status_impl.h`. **ONNX Runtime integration (`onnxruntime/core/session/model_package/`)** The ORT-side glue is wired onto the library through the C inspection and path-resolution entry points. `model_package_context` now translates the library's info tree into ORT-internal structs and parses the `executor_info["ort"]` payload (`model_file`, `external_data`, `session_options`, `provider_options`). When a variant declares `external_data`, `CreateSessionForModelPackage` loads the model from a memory mapping and passes the resolved folder to the session via `kOrtSessionOptionsModelExternalInitializersFileFolderPath`, so external initializers — including those backed by a shared asset — are picked up at `Initialize` time. The experimental `OrtModelPackageApi_*_SinceV28` C entries introduced in #28990 are unchanged. **Documentation and tests** - `model_package/README.md` documents the on-disk layout, manifest and component schemas, shared-asset rules, path resolution, the authoring flow, and commit / prune / validate semantics. - `onnxruntime/core/session/model_package/README.md` documents the ORT consumer-side glue: the `executor_info["ort"]` schema, the variant selection algorithm, the session-creation contract, and the registered experimental C entries. - New library tests cover inspection, authoring, asset hashing, and commit (`model_package/tests/`). The ORT integration tests in `onnxruntime/test/autoep/test_model_package.cc` are reworked against the current C API surface. ### Motivation and Context ORT needs a single library that owns the model package format end to end — not just reading it, but producing it, validating it, and maintaining it on disk with content-addressed shared assets. Consolidating this behind one C API lets ORT, publisher tooling, and third-party consumers share the same parser, path-resolution rules, and on-disk invariants without each reimplementing them, and keeps the library independent of the ORT session runtime. --------- Co-authored-by: jambayk <jambayk@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: jambayk <jambay@github.com>
1 parent 18fa37d commit 6f283a3

33 files changed

Lines changed: 7205 additions & 1924 deletions

cmake/onnxruntime_session.cmake

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@ file(GLOB onnxruntime_session_srcs CONFIGURE_DEPENDS
1313

1414
# Standalone model package library (parsing/inspection with no ORT dependency).
1515
# Compiled as a static library and linked into onnxruntime_session.
16-
# NOTE: ORT intentionally uses the library's internal C++ types directly (model_package::ParsePackage,
17-
# model_package_internal.h) rather than going through its public C API (ModelPackage_*). This avoids
18-
# double-wrapping (ORT C API -> standalone C API -> C++ internals). The public C API exists for
19-
# external consumers (GenAI, FL) who link against the standalone library independently.
16+
# ORT uses the standalone library's public C API (model_package.h) and translates
17+
# the C handles into ORT-internal C++ types inside core/session/model_package/.
2018
set(MODEL_PACKAGE_LIB_DIR "${REPO_ROOT}/model_package")
2119
if(NOT onnxruntime_MINIMAL_BUILD)
2220
set(MODEL_PACKAGE_BUILD_SHARED OFF CACHE BOOL "" FORCE)
@@ -59,7 +57,7 @@ onnxruntime_add_include_to_target(onnxruntime_session onnxruntime_common onnxrun
5957
target_link_libraries(onnxruntime_session PRIVATE onnxruntime_lora)
6058
if(TARGET model_package)
6159
target_link_libraries(onnxruntime_session PRIVATE model_package)
62-
target_include_directories(onnxruntime_session PRIVATE ${MODEL_PACKAGE_LIB_DIR}/include ${MODEL_PACKAGE_LIB_DIR}/src)
60+
target_include_directories(onnxruntime_session PRIVATE ${MODEL_PACKAGE_LIB_DIR}/include)
6361
endif()
6462
if(onnxruntime_ENABLE_INSTRUMENT)
6563
target_compile_definitions(onnxruntime_session PUBLIC ONNXRUNTIME_ENABLE_INSTRUMENT)

include/onnxruntime/core/session/onnxruntime_experimental_c_api.inc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ ORT_EXPERIMENTAL_API(28, OrtStatusPtr, OrtApi_ExperimentalApiTest, _Out_ int64_t
6666
// - OrtModelPackageApi_ModelPackage_GetVariantCount
6767
// - OrtModelPackageApi_ModelPackage_GetVariantNames
6868
// - OrtModelPackageApi_ModelPackage_GetVariantEpName
69+
// - OrtModelPackageApi_ModelPackage_ResolveStringRef
6970
// 4) Select a component and resolve variant:
7071
// - OrtModelPackageApi_SelectComponent
7172
// 5) Query selected variant info (optional):
@@ -212,6 +213,33 @@ ORT_EXPERIMENTAL_API(28, OrtStatusPtr, OrtModelPackageApi_ModelPackage_GetVarian
212213
_In_ const char* variant_name,
213214
_Outptr_result_maybenull_ const char** out_ep)
214215

216+
/** \brief Resolve a path reference declared inside the package against the model_package rules.
217+
*
218+
* Handles the path forms a package may use:
219+
* - "sha256:<hex>" or "sha256:<hex>/<tail>": a content-addressed shared asset. Resolves to
220+
* the asset's on-disk directory (honoring manifest shared_assets overrides), optionally
221+
* joined with the confined tail. Errors if the asset is not declared/discovered.
222+
* - any other value: a relative path resolved against `base_dir` (or the package root when
223+
* `base_dir` is NULL), with portable-layout confinement (no absolute paths, no "..").
224+
*
225+
* When `must_exist` is non-zero the resolved path must exist on disk. `out_path` is owned by
226+
* `ctx` and remains valid until the next call to this function on the same context.
227+
*
228+
* \param[in] ctx The package context returned by OrtModelPackageApi_CreateModelPackageContext.
229+
* \param[in] base_dir Base directory for relative inputs. May be NULL to use the package root.
230+
* \param[in] input The path reference to resolve.
231+
* \param[in] must_exist Non-zero to require that the resolved path exists on disk.
232+
* \param[out] out_path Receives the resolved path string.
233+
*
234+
* \snippet{doc} snippets.dox OrtStatus Return Value
235+
*/
236+
ORT_EXPERIMENTAL_API(28, OrtStatusPtr, OrtModelPackageApi_ModelPackage_ResolveStringRef,
237+
_In_ const OrtModelPackageContext* ctx,
238+
_In_opt_ const char* base_dir,
239+
_In_ const char* input,
240+
_In_ int must_exist,
241+
_Outptr_ const char** out_path)
242+
215243
/** \brief Select a component model and return an opaque component instance.
216244
*
217245
* The variant selection is also performed during this call based on the component

model_package/CMakeLists.txt

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,13 @@ endif()
5252
# ─────────────────────────────────────────────────────────────────────────────
5353

5454
set(MODEL_PACKAGE_SOURCES
55-
src/api.cc
56-
src/parser.cc
55+
src/asset_hasher.cc
56+
src/authoring.cc
57+
src/commit_prune_validate.cc
58+
src/manifest_parser.cc
59+
src/model_package_impl.cc
60+
src/path_resolver.cc
61+
src/sha256.cc
5762
)
5863

5964
if(MODEL_PACKAGE_BUILD_SHARED)
@@ -91,6 +96,45 @@ install(TARGETS model_package
9196
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
9297
)
9398

94-
install(FILES include/model_package_api.h
99+
install(FILES include/model_package_api.h include/model_package.h
95100
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
96101
)
102+
103+
# ─────────────────────────────────────────────────────────────────────────────
104+
# Tests
105+
# ─────────────────────────────────────────────────────────────────────────────
106+
107+
if(MODEL_PACKAGE_BUILD_TESTS)
108+
enable_testing()
109+
add_executable(test_inspection tests/test_inspection.cc)
110+
target_link_libraries(test_inspection PRIVATE model_package nlohmann_json::nlohmann_json)
111+
target_include_directories(test_inspection PRIVATE
112+
${CMAKE_CURRENT_SOURCE_DIR}/include
113+
${CMAKE_CURRENT_SOURCE_DIR}/src
114+
)
115+
add_test(NAME inspection COMMAND test_inspection)
116+
117+
add_executable(test_asset_hashing tests/test_asset_hashing.cc)
118+
target_link_libraries(test_asset_hashing PRIVATE model_package nlohmann_json::nlohmann_json)
119+
target_include_directories(test_asset_hashing PRIVATE
120+
${CMAKE_CURRENT_SOURCE_DIR}/include
121+
${CMAKE_CURRENT_SOURCE_DIR}/src
122+
)
123+
add_test(NAME asset_hashing COMMAND test_asset_hashing)
124+
125+
add_executable(test_authoring tests/test_authoring.cc)
126+
target_link_libraries(test_authoring PRIVATE model_package nlohmann_json::nlohmann_json)
127+
target_include_directories(test_authoring PRIVATE
128+
${CMAKE_CURRENT_SOURCE_DIR}/include
129+
${CMAKE_CURRENT_SOURCE_DIR}/src
130+
)
131+
add_test(NAME authoring COMMAND test_authoring)
132+
133+
add_executable(test_commit tests/test_commit.cc)
134+
target_link_libraries(test_commit PRIVATE model_package nlohmann_json::nlohmann_json)
135+
target_include_directories(test_commit PRIVATE
136+
${CMAKE_CURRENT_SOURCE_DIR}/include
137+
${CMAKE_CURRENT_SOURCE_DIR}/src
138+
)
139+
add_test(NAME commit COMMAND test_commit)
140+
endif()

0 commit comments

Comments
 (0)