Skip to content

Commit a2ca088

Browse files
authored
Merge pull request #2106 from Jdubrick/add-provider-id
RHIDP-15394: add optional id field for inference providers
2 parents 5c2fb71 + 1ffcaa8 commit a2ca088

11 files changed

Lines changed: 229 additions & 18 deletions

File tree

docs/config.html

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,7 +2105,11 @@ <h2 id="unifiedinferenceprovider">UnifiedInferenceProvider</h2>
21052105
values).</p>
21062106
<p>Attributes: type: Canonical provider identifier. Vendor-neutral so it
21072107
survives a future backend change; each backend-specific synthesizer maps
2108-
it to its own provider vocabulary. api_key_env: Name of the environment
2108+
it to its own provider vocabulary. id: Optional identifier emitted as
2109+
the Llama Stack provider_id. When omitted, synthesized as type with
2110+
underscores hyphenated. If set, must be non-empty after stripping
2111+
whitespace and may contain only lowercase letters, digits, underscores,
2112+
and hyphens. api_key_env: Name of the environment
21092113
variable holding the provider API key. Emitted verbatim as
21102114
<code>${env.&lt;name&gt;}</code> so the secret never lands on disk
21112115
resolved. allowed_models: Optional allow-list of model identifiers
@@ -2134,18 +2138,26 @@ <h2 id="unifiedinferenceprovider">UnifiedInferenceProvider</h2>
21342138
Stack provider_type by the synthesizer.</td>
21352139
</tr>
21362140
<tr class="even">
2141+
<td>id</td>
2142+
<td>string</td>
2143+
<td>Optional identifier emitted as the Llama Stack provider_id. When
2144+
omitted, synthesized as type with underscores hyphenated. If set, must
2145+
be non-empty after stripping whitespace and may contain only lowercase
2146+
letters, digits, underscores, and hyphens.</td>
2147+
</tr>
2148+
<tr class="odd">
21372149
<td>api_key_env</td>
21382150
<td>string</td>
21392151
<td>Name of the environment variable holding the provider API key.
21402152
Emitted as a ${env.name} reference so the secret is never written to
21412153
disk in resolved form.</td>
21422154
</tr>
2143-
<tr class="odd">
2155+
<tr class="even">
21442156
<td>allowed_models</td>
21452157
<td>array</td>
21462158
<td>Optional allow-list of model identifiers for this provider.</td>
21472159
</tr>
2148-
<tr class="even">
2160+
<tr class="odd">
21492161
<td>extra</td>
21502162
<td>object</td>
21512163
<td>Additional provider-config keys merged verbatim into the synthesized

docs/config.json

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@
458458
},
459459
"CompactionConfiguration": {
460460
"additionalProperties": false,
461-
"description": "Configuration for conversation history compaction.\n\nCompaction summarizes older conversation turns when their estimated\ntoken count approaches the context window limit, keeping the\nconversation usable instead of failing with HTTP 413. The\nconfiguration here controls when compaction triggers and how much\nrecent context is preserved verbatim.\n\nAttributes:\n enabled: Master switch. When False, compaction never triggers\n and other fields are inert.\n threshold_ratio: Trigger compaction when estimated input tokens\n exceed this fraction of the model's context window\n (clamped to 0.0..1.0).\n token_floor: Minimum estimated token count before compaction\n can trigger, regardless of threshold_ratio. Prevents\n triggering on very small context windows.\n buffer_turns: Initial number of recent turns to keep verbatim.\n The runtime applies a degrading guard — if these turns\n exceed the available budget, it reduces buffer_turns by\n one repeatedly until the budget fits, down to zero.\n buffer_max_ratio: Hard cap on the fraction of the context\n window the buffer zone may occupy, regardless of\n buffer_turns.",
461+
"description": "Configuration for conversation history compaction.\n\nCompaction summarizes older conversation turns when their estimated\ntoken count approaches the context window limit, keeping the\nconversation usable instead of failing with HTTP 413. The\nconfiguration here controls when compaction triggers and how much\nrecent context is preserved verbatim.\n\nAttributes:\n enabled: Master switch. When False, compaction never triggers\n and other fields are inert.\n threshold_ratio: Trigger compaction when estimated input tokens\n exceed this fraction of the model's context window\n (clamped to 0.0..1.0).\n token_floor: Minimum estimated token count before compaction\n can trigger, regardless of threshold_ratio. Prevents\n triggering on very small context windows.\n buffer_turns: Initial number of recent turns to keep verbatim.\n The runtime applies a degrading guard \u2014 if these turns\n exceed the available budget, it reduces buffer_turns by\n one repeatedly until the budget fits, down to zero.\n buffer_max_ratio: Hard cap on the fraction of the context\n window the buffer zone may occupy, regardless of\n buffer_turns.",
462462
"properties": {
463463
"enabled": {
464464
"default": false,
@@ -575,7 +575,7 @@
575575
},
576576
"compaction": {
577577
"$ref": "#/components/schemas/CompactionConfiguration",
578-
"description": "Controls when conversation history is summarized to keep the model's input below the context window limit. Disabled by default when disabled, requests that exceed the window continue to surface as HTTP 413.",
578+
"description": "Controls when conversation history is summarized to keep the model's input below the context window limit. Disabled by default \u2014 when disabled, requests that exceed the window continue to surface as HTTP 413.",
579579
"title": "Conversation compaction configuration"
580580
},
581581
"approvals": {
@@ -885,7 +885,7 @@
885885
"minimum": 0,
886886
"type": "integer"
887887
},
888-
"description": "Map of fully-qualified model identifier (e.g., \"openai/gpt-4o-mini\") to context window size in tokens. Used by the conversation compaction trigger to decide when older turns must be summarized before the input exceeds the window. Models absent from this map have no registered window callers fall back to their own default or skip the token-based trigger.",
888+
"description": "Map of fully-qualified model identifier (e.g., \"openai/gpt-4o-mini\") to context window size in tokens. Used by the conversation compaction trigger to decide when older turns must be summarized before the input exceeds the window. Models absent from this map have no registered window \u2014 callers fall back to their own default or skip the token-based trigger.",
889889
"title": "Per-model context window sizes (tokens)",
890890
"type": "object"
891891
},
@@ -1719,7 +1719,7 @@
17191719
},
17201720
"UnifiedInferenceProvider": {
17211721
"additionalProperties": false,
1722-
"description": "A high-level inference provider entry for unified-mode synthesis.\n\nOperators describe inference providers at this high level (backend-agnostic\nvocabulary) instead of authoring raw Llama Stack provider blocks. The\nsynthesizer (`apply_high_level_inference`) expands each entry into a Llama\nStack `providers.inference` entry, mapping `type` to a `provider_type` and\nemitting `${env.<VAR>}` references for secrets (never literal values).\n\nAttributes:\n type: Canonical provider identifier. Vendor-neutral so it survives a\n future backend change; each backend-specific synthesizer maps it to\n its own provider vocabulary.\n api_key_env: Name of the environment variable holding the provider API\n key. Emitted verbatim as `${env.<name>}` so the secret never lands\n on disk resolved.\n allowed_models: Optional allow-list of model identifiers passed through\n to the synthesized provider config.\n extra: Additional provider-config keys merged verbatim into the\n synthesized provider's `config` block — an escape hatch for\n provider-specific knobs not modeled here.",
1722+
"description": "A high-level inference provider entry for unified-mode synthesis.\n\nOperators describe inference providers at this high level (backend-agnostic\nvocabulary) instead of authoring raw Llama Stack provider blocks. The\nsynthesizer (`apply_high_level_inference`) expands each entry into a Llama\nStack `providers.inference` entry, mapping `type` to a `provider_type` and\nemitting `${env.<VAR>}` references for secrets (never literal values).\n\nAttributes:\n type: Canonical provider identifier. Vendor-neutral so it survives a\n future backend change; each backend-specific synthesizer maps it to\n its own provider vocabulary.\n id: Optional identifier emitted as the Llama Stack provider_id. When\n omitted, synthesized as type with underscores hyphenated. If set,\n must be non-empty after stripping whitespace and may contain only\n lowercase letters, digits, underscores, and hyphens.\n api_key_env: Name of the environment variable holding the provider API\n key. Emitted verbatim as `${env.<name>}` so the secret never lands\n on disk resolved.\n allowed_models: Optional allow-list of model identifiers passed through\n to the synthesized provider config.\n extra: Additional provider-config keys merged verbatim into the\n synthesized provider's `config` block \u2014 an escape hatch for\n provider-specific knobs not modeled here.",
17231723
"properties": {
17241724
"type": {
17251725
"description": "Canonical, backend-agnostic provider identifier mapped to a Llama Stack provider_type by the synthesizer.",
@@ -1737,6 +1737,13 @@
17371737
"title": "Provider type",
17381738
"type": "string"
17391739
},
1740+
"id": {
1741+
"type": "string",
1742+
"nullable": true,
1743+
"default": null,
1744+
"description": "Optional identifier emitted as the Llama Stack provider_id. When omitted, synthesized as type with underscores hyphenated. If set, must be non-empty after stripping whitespace and may contain only lowercase letters, digits, underscores, and hyphens.",
1745+
"title": "Provider ID"
1746+
},
17401747
"api_key_env": {
17411748
"type": "string",
17421749
"nullable": true,

docs/config.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,10 @@ Attributes:
794794
type: Canonical provider identifier. Vendor-neutral so it survives a
795795
future backend change; each backend-specific synthesizer maps it to
796796
its own provider vocabulary.
797+
id: Optional identifier emitted as the Llama Stack provider_id. When
798+
omitted, synthesized as type with underscores hyphenated. If set,
799+
must be non-empty after stripping whitespace and may contain only
800+
lowercase letters, digits, underscores, and hyphens.
797801
api_key_env: Name of the environment variable holding the provider API
798802
key. Emitted verbatim as `${env.<name>}` so the secret never lands
799803
on disk resolved.
@@ -807,6 +811,7 @@ Attributes:
807811
| Field | Type | Description |
808812
|----------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
809813
| type | string | Canonical, backend-agnostic provider identifier mapped to a Llama Stack provider_type by the synthesizer. |
814+
| id | string | Optional identifier emitted as the Llama Stack provider_id. When omitted, synthesized as type with underscores hyphenated. If set, must be non-empty after stripping whitespace and may contain only lowercase letters, digits, underscores, and hyphens. |
810815
| api_key_env | string | Name of the environment variable holding the provider API key. Emitted as a ${env.<name>} reference so the secret is never written to disk in resolved form. |
811816
| allowed_models | array | Optional allow-list of model identifiers for this provider. |
812817
| extra | object | Additional provider-config keys merged verbatim into the synthesized provider's config block. |

docs/config.puml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,8 @@ class "UnifiedInferenceProvider" as src.models.config.UnifiedInferenceProvider {
303303
allowed_models : Optional[list[str]]
304304
api_key_env : Optional[str]
305305
extra : dict[str, object]
306-
type : Literal['openai', 'sentence_transformers', 'azure', 'vertexai', 'watsonx', 'vllm_rhaiis', 'vllm_rhel_ai']
306+
id : str | None
307+
type : Literal['openai', 'ollama', 'vllm', 'sentence_transformers', 'azure', 'vertexai', 'watsonx', 'vllm_rhaiis', 'vllm_rhel_ai']
307308
}
308309
class "UnifiedLlamaStackConfig" as src.models.config.UnifiedLlamaStackConfig {
309310
baseline : Literal['default', 'empty']

docs/openapi.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20355,6 +20355,18 @@
2035520355
"title": "Provider type",
2035620356
"description": "Canonical, backend-agnostic provider identifier mapped to a Llama Stack provider_type by the synthesizer."
2035720357
},
20358+
"id": {
20359+
"anyOf": [
20360+
{
20361+
"type": "string"
20362+
},
20363+
{
20364+
"type": "null"
20365+
}
20366+
],
20367+
"title": "Provider ID",
20368+
"description": "Optional identifier emitted as the Llama Stack provider_id. When omitted, synthesized as type with underscores hyphenated. If set, must be non-empty after stripping whitespace and may contain only lowercase letters, digits, underscores, and hyphens."
20369+
},
2035820370
"api_key_env": {
2035920371
"anyOf": [
2036020372
{
@@ -20395,7 +20407,7 @@
2039520407
"type"
2039620408
],
2039720409
"title": "UnifiedInferenceProvider",
20398-
"description": "A high-level inference provider entry for unified-mode synthesis.\n\nOperators describe inference providers at this high level (backend-agnostic\nvocabulary) instead of authoring raw Llama Stack provider blocks. The\nsynthesizer (`apply_high_level_inference`) expands each entry into a Llama\nStack `providers.inference` entry, mapping `type` to a `provider_type` and\nemitting `${env.<VAR>}` references for secrets (never literal values).\n\nAttributes:\n type: Canonical provider identifier. Vendor-neutral so it survives a\n future backend change; each backend-specific synthesizer maps it to\n its own provider vocabulary.\n api_key_env: Name of the environment variable holding the provider API\n key. Emitted verbatim as `${env.<name>}` so the secret never lands\n on disk resolved.\n allowed_models: Optional allow-list of model identifiers passed through\n to the synthesized provider config.\n extra: Additional provider-config keys merged verbatim into the\n synthesized provider's `config` block \u2014 an escape hatch for\n provider-specific knobs not modeled here."
20410+
"description": "A high-level inference provider entry for unified-mode synthesis.\n\nOperators describe inference providers at this high level (backend-agnostic\nvocabulary) instead of authoring raw Llama Stack provider blocks. The\nsynthesizer (`apply_high_level_inference`) expands each entry into a Llama\nStack `providers.inference` entry, mapping `type` to a `provider_type` and\nemitting `${env.<VAR>}` references for secrets (never literal values).\n\nAttributes:\n type: Canonical provider identifier. Vendor-neutral so it survives a\n future backend change; each backend-specific synthesizer maps it to\n its own provider vocabulary.\n id: Optional identifier emitted as the Llama Stack provider_id. When\n omitted, synthesized as type with underscores hyphenated. If set,\n must be non-empty after stripping whitespace and may contain only\n lowercase letters, digits, underscores, and hyphens.\n api_key_env: Name of the environment variable holding the provider API\n key. Emitted verbatim as `${env.<name>}` so the secret never lands\n on disk resolved.\n allowed_models: Optional allow-list of model identifiers passed through\n to the synthesized provider config.\n extra: Additional provider-config keys merged verbatim into the\n synthesized provider's `config` block \u2014 an escape hatch for\n provider-specific knobs not modeled here."
2039920411
},
2040020412
"UnifiedLlamaStackConfig": {
2040120413
"properties": {

examples/profiles/inline-faiss.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
# providers:
1212
# - type: openai
1313
# api_key_env: OPENAI_API_KEY
14+
# # Multiple backends of the same type need distinct id values:
15+
# # - type: vllm
16+
# # id: vllm-prod
17+
# # api_key_env: VLLM_PROD_KEY
18+
# # - type: vllm
19+
# # id: vllm-staging
20+
# # api_key_env: VLLM_STAGING_KEY
1421
# llama_stack:
1522
# use_as_library_client: true
1623
# config:

src/client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ async def _load_library_client(self, config: LlamaStackConfiguration) -> None:
6464
"""
6565
logger.info("Using Llama stack as library client")
6666

67+
# Configure logging before synthesis/enrichment so INFO lines from those
68+
# steps are not dropped. Without handlers, Python's lastResort only
69+
# emits WARNING and above — which is why replace logs disappeared after
70+
# moving from warning to info.
71+
setup_logging()
72+
6773
if config.library_client_config_path is not None and config.config is None:
6874
self._config_path = self._enrich_library_config(
6975
config.library_client_config_path

src/llama_stack_configuration.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -718,12 +718,14 @@ def apply_high_level_inference(
718718
719719
Each high-level provider is mapped to a Llama Stack ``providers.inference``
720720
entry via :data:`PROVIDER_TYPE_MAP`. The emitted ``provider_id`` is the
721-
provider ``type`` with underscores hyphenated, so an inline embedder declared
722-
as ``sentence_transformers`` becomes ``sentence-transformers`` and matches the
721+
optional explicit high-level ``id`` when set; otherwise the provider ``type``
722+
with underscores hyphenated, so an inline embedder declared as
723+
``sentence_transformers`` becomes ``sentence-transformers`` and matches the
723724
baseline's ecosystem convention (e.g. the default embedding model reference).
724-
An entry whose ``provider_id`` already exists in the baseline is replaced; new
725-
ones are appended. Secrets are emitted as ``${env.<VAR>}`` references, never
726-
resolved values (R6).
725+
An entry whose ``provider_id`` already exists in the baseline (or was emitted
726+
by an earlier high-level entry) is replaced with an info log; new ones are
727+
appended. Secrets are emitted as ``${env.<VAR>}`` references, never resolved
728+
values (R6).
727729
728730
Parameters:
729731
ls_config: The Llama Stack configuration being synthesized (modified in
@@ -743,7 +745,7 @@ def apply_high_level_inference(
743745

744746
for provider in providers:
745747
provider_type = provider["type"]
746-
emitted_id = provider_type.replace("_", "-")
748+
emitted_id = provider.get("id") or provider_type.replace("_", "-")
747749
ls_provider_type = PROVIDER_TYPE_MAP[provider_type]
748750
entry: dict[str, Any] = {
749751
"provider_id": emitted_id,
@@ -764,6 +766,11 @@ def apply_high_level_inference(
764766
# Replace a baseline provider with the same id, else append.
765767
for index, existing in enumerate(inference_list):
766768
if isinstance(existing, dict) and existing.get("provider_id") == emitted_id:
769+
logger.info(
770+
"Replacing existing inference provider with "
771+
"provider_id=%r; a later high-level entry overwrote it",
772+
emitted_id,
773+
)
767774
inference_list[index] = entry
768775
break
769776
else:

0 commit comments

Comments
 (0)