Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "interscript",
"version": "3.2.0",
"version": "3.3.0",
"description": "Interscript TypeScript runtime — interoperable script conversion",
"type": "module",
"main": "./dist/index.js",
Expand Down
15 changes: 15 additions & 0 deletions src/ml/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,21 @@ export { registerModel, loadModel, registeredKinds, resetModels } from "./regist

export { createSession, detectBackend } from "./session/index.js"

/**
* @deprecated CDN-base override for the deprecated manifest-based
* provisioner. IMF models resolve through the GitHub Releases
* index instead.
*/
export { setModelBase, getModelBase } from "./provision/base.js"

/**
* @deprecated The manifest-based provisioner (loose .onnx + sidecars
* behind a version→URL manifest) is superseded by the IMF registry:
* `import { imf } from "interscript/ml"` → `imf.resolve("<model-id>")`
* (GitHub Releases index, sha256-verified zips). Kept for explicit-URL
* provisioning and inline-manifest (test/air-gapped) use; no manifest
* is published anymore.
*/
export {
loadManifest,
resolveManifestEntry,
Expand All @@ -42,7 +55,9 @@ export {
setInlineManifest,
setManifestUrl,
type AssetVariant,
/** @deprecated — see the block comment above */
type Manifest,
/** @deprecated — see the block comment above */
type ManifestModelEntry,
} from "./provision/manifest.js"

Expand Down
6 changes: 4 additions & 2 deletions src/ml/provision/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,10 @@ async function resolveModelUrl(
const entry = await resolveManifestEntry(ref.kind, ref.id)
if (!entry) {
throw new Error(
`No manifest entry for kind=${ref.kind} id=${ref.id}. ` +
`Pass an explicit \`url\` on the ModelRef or pin a task version in the manifest.`,
`No manifest entry for kind=${ref.kind} id=${ref.id}. The manifest-based ` +
`provisioner is deprecated; load models via \`import { imf } from "interscript/ml"\` ` +
`and \`imf.resolve("${ref.id}")\` (GitHub Releases index, sha256-verified), ` +
`or pass an explicit \`url\` on the ModelRef.`,
)
}
const { primary } = artifactUrls(entry, variant, format)
Expand Down
24 changes: 14 additions & 10 deletions src/ml/provision/manifest.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
/**
* Manifest-driven model resolution.
* Manifest-driven model resolution. DEPRECATED — superseded by the IMF
* registry (`src/ml/imf/`, published at `imf` from "interscript/ml"):
* models.yaml on GitHub Releases with sha256 sidecar verification.
*
* The source of truth for "what model version is current" lives in
* the `@interscript/models` npm package (a tiny JSON manifest kept
* in lockstep with GH Releases in `interscript/ml-models`).
* No manifest is published anymore (the `@interscript/models` npm
* package was never released; the CDN manifest.json URL is dead).
* This module remains for explicit-URL provisioning and
* inline-manifest (test / air-gapped) use.
*
* Resolution order for the manifest itself:
* 1. Programmatically injected via `setManifestUrl()` or
* `setInlineManifest()` (tests, air-gapped envs).
* 2. The `@interscript/models` package, when installed.
* 3. A remote JSON URL on the CDN (`manifest.json` next to the
* 2. A remote JSON URL on the CDN (`manifest.json` next to the
* release assets).
*
* See `ml-models/TODO.distribution/04-npm-packages.md` for the
* full MECE breakdown of who owns what.
*/

import { getModelBase } from "./base.js"
Expand Down Expand Up @@ -99,7 +98,12 @@ export async function loadManifest(): Promise<Manifest> {
const url = manifestUrlOverride ?? defaultManifestUrl()
const res = await fetch(url)
if (!res.ok) {
throw new Error(`Failed to load model manifest from ${url}: ${res.status} ${res.statusText}`)
throw new Error(
`Failed to load model manifest from ${url}: ${res.status} ${res.statusText}. ` +
`The manifest-based provisioner is deprecated and no manifest is published; ` +
`load models via \`import { imf } from "interscript/ml"\` and \`imf.resolve("<model-id>")\` ` +
`(GitHub Releases index, sha256-verified), or pass an explicit \`url\` on the ModelRef.`,
)
}
const json = (await res.json()) as Manifest
cachedManifest = json
Expand Down
21 changes: 21 additions & 0 deletions test/ml/provision.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
type Manifest,
type ManifestModelEntry,
} from "../../src/ml/provision/manifest.js"
import { provisionModel } from "../../src/ml/provision/index.js"

const SAMPLE_ENTRY: ManifestModelEntry = {
status: "stable",
Expand Down Expand Up @@ -115,4 +116,24 @@ describe("manifest provisioner", () => {
expect(() => artifactUrls(malformed)).toThrow(/task name/)
})
})

describe("manifest-less resolution errors point at the IMF registry", () => {
it("rejects with imf guidance when no manifest is published and no url given", async () => {
setInlineManifest(null)
try {
await expect(provisionModel({ kind: "secryst", id: "unresolved" })).rejects.toThrow(
/imf\.resolve\(/,
)
} finally {
setInlineManifest(SAMPLE_MANIFEST)
}
})

it("rejects with imf guidance when the manifest has no matching entry", async () => {
setInlineManifest(SAMPLE_MANIFEST) // has no entry for this id
await expect(provisionModel({ kind: "secryst", id: "unresolved" })).rejects.toThrow(
/imf\.resolve\(/,
)
})
})
})
Loading