You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
|`bundles`| array | no |[Bundle list](#bundles). v0 accepts at most one bundle; omit it for a provider-only extension. |
41
+
|`providers`| array | no |[Model providers](#providers) contributed to the unified model-provider registry. |
41
42
|`capabilities`| object | no |[Optional capability flags](#capabilities). Defaults to all-false. |
42
43
|`$schema`| string | no | Optional pointer to this JSON Schema; editors use it for autocomplete. |
43
44
44
45
`additionalProperties: false` — any field not listed here is rejected with a typed error. Reserved names (`services`, `routes`, `hooks`, `starterProjects`, `userConfig`) are documented under [Deferred fields](#deferred-fields) and surface a more specific error code.
45
46
47
+
An extension must declare at least one entry in either `bundles` or `providers`. It can declare both when one package contributes components and model providers.
48
+
46
49
## `lfx`: compatibility declaration
47
50
48
51
```json
@@ -68,7 +71,66 @@ The runtime compares `str(BUNDLE_API_VERSION)` against this list. A mismatch fai
68
71
|`name`| string | Bundle name; addressable as `ext:<bundle>:<Class>@<slot>`. Lowercase snake_case, starts with a letter, 2-64 chars. |
69
72
|`path`| string | Path to the bundle directory, relative to the manifest. Must not start with `/` or contain `..`. |
70
73
71
-
v0 enforces `minItems: 1, maxItems: 1`; multi-bundle extensions are rejected with `multi-bundle-deferred-in-this-milestone` and ship in a later epic.
74
+
v0 enforces `maxItems: 1`; multi-bundle extensions are rejected with `multi-bundle-deferred-in-this-milestone` and ship in a later epic. The list can be empty when the extension declares at least one model provider.
75
+
76
+
## `providers`
77
+
78
+
A provider-only extension can add a provider without adding a component bundle:
|`name`| string | yes | Canonical provider name used by existing saved flows and provider selectors. |
116
+
|`provider_id`| string | no | Stable lowercase machine identity used by policy and extension compatibility. Must match `^[a-z0-9][a-z0-9._-]*$`. Legacy manifests can omit it and receive a deterministic ID derived from `name`. |
117
+
|`display_name`| string | no | User-facing label. It can change without changing `provider_id` or saved-flow identity. |
118
+
|`aliases`| array of strings | no | Unique legacy names accepted when resolving the provider's stable identity. |
119
+
|`metadata`| object | yes | Provider icon, variables, API documentation URL, and mapping. `mapping.model_class` must be non-empty. |
120
+
|`model_class`| object | no | Lazy LLM class import with `module`, `attr`, and optional `install_hint`. Omit it when reusing an already-registered class. |
121
+
|`embedding`| object | no | Optional embedding class import and parameter mapping. Includes `class_name`, `module`, `attr`, `param_mapping_key`, `param_mapping`, and optional `install_hint`. |
122
+
|`api_key_required`| bool | no | Whether unified runtime helpers reject missing API-key credentials. Defaults to `true`. |
123
+
|`live`| bool | no | Enables always-on live model discovery. Mutually exclusive with `conditional_live`. |
124
+
|`conditional_live`| bool | no | Enables live discovery only when the provider has a custom endpoint configured. Mutually exclusive with `live`. |
125
+
|`live_discovery`| string | no | Lazy `module:callable` that receives `(user_id, model_type)` and returns live model rows. |
126
+
|`validator`| string | no | Lazy `module:callable` that validates `(provider, variables, model)` and raises on invalid credentials. |
127
+
|`catalog_loader`| string | no | Lazy `module:callable` returning the provider's static model metadata rows. |
128
+
129
+
`catalog_loader` must return a flat `list[dict]`. Every row requires a non-empty `name`; `model_type` can be `llm` or `embeddings` and defaults to `llm`. Langflow overwrites any supplied `provider` value with the descriptor's canonical `name`, supplies the provider icon when omitted, and rejects duplicate `(model_type, name)` identities. Deployments that require an extension catalog can call `validate_registered_provider_catalogs()` or `get_registry_snapshot(validate_catalogs=True)` during readiness.
130
+
131
+
Providers that use ambient authentication or need no credentials should set `api_key_required` to `false`. They remain eligible for unified model options when `metadata.variables` is empty or contains only optional configuration fields.
132
+
133
+
Built-in providers take precedence over extension declarations. A colliding provider is skipped without preventing other providers or components in the extension from loading.
72
134
73
135
## `capabilities`
74
136
@@ -127,6 +189,8 @@ The loader and validator both emit typed errors keyed by the manifest field that
127
189
|`multi-bundle-deferred-in-this-milestone`|`bundles` has more than one entry. |
128
190
|`path-escape`| A `bundles[].path` resolves outside the manifest root (typically a symlink). |
129
191
|`bundle-path-not-found`|`bundles[].path` does not exist or is not a directory. |
192
+
|`provider-invalid`| A provider descriptor or one of its lazy import paths is malformed. The invalid provider is skipped. |
193
+
|`provider-skipped`| A provider name collides with a built-in or previously loaded provider. The existing provider wins. |
130
194
131
195
Run `lfx extension validate <path>` to see every error as a structured object with `code`, `message`, `location`, `hint`, and `ref_url`.
0 commit comments