Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
030b77e
fix(BA-5983): make ModelConfig GQL input fields optional
jopemachine May 8, 2026
a1fd8c2
chore: add news fragment for PR #11531
jopemachine May 8, 2026
b84c950
chore: update api schema dump
jopemachine May 8, 2026
91472f4
refactor(BA-5983): introduce v2 ModelConfig/ModelDefinition Input DTOs
jopemachine May 8, 2026
47012b5
chore(BA-5983): trim repetitive descriptions on Model* input types
jopemachine May 8, 2026
9c1e003
chore: update api schema dump
jopemachine May 8, 2026
e82cd8f
refactor(BA-5983): make to_draft a method of ModelDefinitionInput
jopemachine May 10, 2026
709dc9e
test(BA-5983): cover ModelDefinitionInput merge + to_resolved behavior
jopemachine May 11, 2026
c52e6f0
docs: refer to RevisionDraft.merge instead of removed helper
jopemachine May 11, 2026
aa14f1f
test(BA-5983): parametrize missing-required-field merge tests
jopemachine May 11, 2026
d3cf04c
test(BA-5983): parametrize remaining merge-behavior test groups
jopemachine May 11, 2026
83b3ac4
fix(BA-5983): preserve unset semantics in ModelDefinitionInput.to_draft
jopemachine May 11, 2026
8f74efc
test(BA-5983): add DB-backed revision merge test
jopemachine May 11, 2026
33b5ab2
test(BA-5983): seed DB baseline via fixture; parametrize on input/result
jopemachine May 11, 2026
58eb89b
test(BA-5983): one fixture per DB baseline shape; parametrize only in…
jopemachine May 11, 2026
90d5645
test(BA-5983): consolidate merge tests into the DB-backed file
jopemachine May 11, 2026
8366021
test(BA-5983): drop tests added in this PR
jopemachine May 11, 2026
139acc4
refactor(BA-5983): defer default-value application to strict Pydantic…
jopemachine May 11, 2026
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
1 change: 1 addition & 0 deletions changes/11531.fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make ModelConfig / ModelDefinition / ModelServiceConfig / ModelHealthCheck GraphQL input fields optional so addModelRevision can inherit values from the runtime variant, model-definition.yaml, or revision preset.
26 changes: 13 additions & 13 deletions docs/manager/graphql-reference/supergraph.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -9235,10 +9235,10 @@ input ModelConfigInput
@join__type(graph: STRAWBERRY)
{
"""Name of the model."""
name: String!
name: String = null

"""Path to the model file."""
modelPath: String!
modelPath: String = null

"""Configuration for the model service."""
service: ModelServiceConfigInput = null
Expand All @@ -9264,7 +9264,7 @@ input ModelDefinitionInput
@join__type(graph: STRAWBERRY)
{
"""List of models in the model definition."""
models: [ModelConfigInput!]!
models: [ModelConfigInput!] = null
}

"""
Expand Down Expand Up @@ -9431,22 +9431,22 @@ input ModelHealthCheckInput
@join__type(graph: STRAWBERRY)
{
"""Interval in seconds between health checks."""
interval: Float! = 10
interval: Float = null

"""Path to check for health status."""
path: String!
path: String = null

"""Maximum number of retries for health check."""
maxRetries: Int! = 10
maxRetries: Int = null

"""Maximum time in seconds to wait for a health check response."""
maxWaitTime: Float! = 15
maxWaitTime: Float = null

"""Expected HTTP status code for a healthy response."""
expectedStatusCode: Int! = 200
expectedStatusCode: Int = null

"""Initial delay in seconds before the first health check."""
initialDelay: Float! = 60
initialDelay: Float = null
}

"""Added in 26.4.2. Metadata describing a model entry."""
Expand Down Expand Up @@ -9803,16 +9803,16 @@ input ModelServiceConfigInput
"""
List of pre-start actions to execute before starting the model service.
"""
preStartActions: [PreStartActionInput!]!
preStartActions: [PreStartActionInput!] = null

"""Command to start the model service."""
startCommand: [String!] = null

"""Shell configured for the model service."""
shell: String! = "/bin/bash"
shell: String = null

"""Port number for the model service. Must be greater than 1."""
port: Int!
"""Port number for the model service."""
port: Int = null

"""Health check configuration for the model service."""
healthCheck: ModelHealthCheckInput = null
Expand Down
26 changes: 13 additions & 13 deletions docs/manager/graphql-reference/v2-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -6045,10 +6045,10 @@ Added in 26.4.0. Configuration for a single model within a model definition.
"""
input ModelConfigInput {
"""Name of the model."""
name: String!
name: String = null

"""Path to the model file."""
modelPath: String!
modelPath: String = null

"""Configuration for the model service."""
service: ModelServiceConfigInput = null
Expand All @@ -6070,7 +6070,7 @@ Added in 26.4.0. Model definition containing a list of model configurations.
"""
input ModelDefinitionInput {
"""List of models in the model definition."""
models: [ModelConfigInput!]!
models: [ModelConfigInput!] = null
}

"""
Expand Down Expand Up @@ -6218,22 +6218,22 @@ type ModelHealthCheck {
"""Added in 26.4.0. Health check configuration for a model service."""
input ModelHealthCheckInput {
"""Interval in seconds between health checks."""
interval: Float! = 10
interval: Float = null

"""Path to check for health status."""
path: String!
path: String = null

"""Maximum number of retries for health check."""
maxRetries: Int! = 10
maxRetries: Int = null

"""Maximum time in seconds to wait for a health check response."""
maxWaitTime: Float! = 15
maxWaitTime: Float = null

"""Expected HTTP status code for a healthy response."""
expectedStatusCode: Int! = 200
expectedStatusCode: Int = null

"""Initial delay in seconds before the first health check."""
initialDelay: Float! = 60
initialDelay: Float = null
}

"""Added in 26.4.2. Metadata describing a model entry."""
Expand Down Expand Up @@ -6554,16 +6554,16 @@ input ModelServiceConfigInput {
"""
List of pre-start actions to execute before starting the model service.
"""
preStartActions: [PreStartActionInput!]!
preStartActions: [PreStartActionInput!] = null

"""Command to start the model service."""
startCommand: [String!] = null

"""Shell configured for the model service."""
shell: String! = "/bin/bash"
shell: String = null

"""Port number for the model service. Must be greater than 1."""
port: Int!
"""Port number for the model service."""
port: Int = null

"""Health check configuration for the model service."""
healthCheck: ModelHealthCheckInput = null
Expand Down
77 changes: 73 additions & 4 deletions src/ai/backend/common/dto/manager/v2/deployment/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
from pydantic import Field, field_validator

from ai.backend.common.api_handlers import SENTINEL, BaseRequestModel, Sentinel
from ai.backend.common.config import ModelDefinitionDraft
from ai.backend.common.config import (
ModelDefinitionDraft,
PreStartAction,
)
from ai.backend.common.data.model_deployment.types import (
DeploymentStrategy,
RouteHealthStatus,
Expand Down Expand Up @@ -80,10 +83,15 @@
"EnvironmentVariablesInput",
"ExtraVFolderMountInput",
"ImageInput",
"ModelConfigInput",
"ModelDefinitionInput",
"ModelDeploymentMetadataInput",
"ModelDeploymentNetworkAccessInput",
"ModelHealthCheckInput",
"ModelMetadataInput",
"ModelMountConfigInput",
"ModelRuntimeConfigInput",
"ModelServiceConfigInput",
"ReplicaFilter",
"ReplicaOrder",
"ReplicaStatusFilter",
Expand Down Expand Up @@ -116,6 +124,67 @@
)


class ModelHealthCheckInput(BaseRequestModel):
interval: float | None = None
path: str | None = None
max_retries: int | None = None
max_wait_time: float | None = None
expected_status_code: int | None = None
initial_delay: float | None = None


class ModelMetadataInput(BaseRequestModel):
author: str | None = None
title: str | None = None
version: str | None = None
created: str | None = None
last_modified: str | None = None
description: str | None = None
task: str | None = None
category: str | None = None
architecture: str | None = None
framework: list[str] | None = None
label: list[str] | None = None
license: str | None = None
min_resource: dict[str, Any] | None = None


class ModelServiceConfigInput(BaseRequestModel):
pre_start_actions: list[PreStartAction] | None = None
start_command: list[str] | None = None
shell: str | None = None
port: int | None = None
health_check: ModelHealthCheckInput | None = None


class ModelConfigInput(BaseRequestModel):
name: str | None = None
model_path: str | None = None
service: ModelServiceConfigInput | None = None
metadata: ModelMetadataInput | None = None


class ModelDefinitionInput(BaseRequestModel):
"""All-optional v2 input mirror of :class:`ModelDefinitionDraft`.

Fields a request omits are filled by lower-priority sources in the
revision merge chain (runtime variant baseline, revision preset,
vfolder ``model-definition.yaml``, ``model_mount_destination``
default). Required-field enforcement happens later in
``ModelDefinitionDraft.to_resolved`` after the merge.
"""

models: list[ModelConfigInput] | None = None


def to_model_definition_draft(
input: ModelDefinitionInput | None,
Comment thread
jopemachine marked this conversation as resolved.
Outdated
) -> ModelDefinitionDraft | None:
if input is None:
return None
return ModelDefinitionDraft.model_validate(input.model_dump())


class ClusterConfigInput(BaseRequestModel):
"""Cluster configuration input for a revision."""

Expand Down Expand Up @@ -233,7 +302,7 @@ class CreateRevisionInputDTO(BaseRequestModel):
image: ImageInput = Field(description="Container image")
model_runtime_config: ModelRuntimeConfigInput = Field(description="Runtime configuration")
model_mount_config: ModelMountConfigInput = Field(description="Model mount configuration")
model_definition: ModelDefinitionDraft | None = Field(
model_definition: ModelDefinitionInput | None = Field(
default=None,
description="Model definition to override the default values generated by the server",
)
Expand Down Expand Up @@ -269,7 +338,7 @@ class AddRevisionGQLInputDTO(BaseRequestModel):
image: ImageInput = Field(description="Container image")
model_runtime_config: ModelRuntimeConfigInput = Field(description="Runtime configuration")
model_mount_config: ModelMountConfigInput = Field(description="Model mount configuration")
model_definition: ModelDefinitionDraft | None = Field(
model_definition: ModelDefinitionInput | None = Field(
default=None,
description="Model definition to override the default values generated by the server",
)
Expand Down Expand Up @@ -396,7 +465,7 @@ class RevisionInput(BaseRequestModel):
default="/models", description="Mount destination for model vfolder"
)
model_definition_path: str = Field(description="Path to model definition file")
model_definition: ModelDefinitionDraft | None = Field(
model_definition: ModelDefinitionInput | None = Field(
default=None,
description="Model definition to override the default values generated by the server",
)
Expand Down
5 changes: 3 additions & 2 deletions src/ai/backend/manager/api/adapters/deployment/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
SyncReplicaInput,
UpdateDeploymentInput,
UpsertDeploymentPolicyInput,
to_model_definition_draft,
)
from ai.backend.common.dto.manager.v2.deployment.response import (
AccessTokenNode,
Expand Down Expand Up @@ -505,7 +506,7 @@ async def create(
else None,
),
mounts=mounts_creator,
model_definition=initial_revision.model_definition,
model_definition=to_model_definition_draft(initial_revision.model_definition),
revision_preset_id=initial_revision.revision_preset_id,
execution=ExecutionSpec(
runtime_variant_id=initial_revision.model_runtime_config.runtime_variant_id,
Expand Down Expand Up @@ -1110,7 +1111,7 @@ async def add_revision(
else None,
inference_runtime_config=input.model_runtime_config.inference_runtime_config,
),
model_definition=input.model_definition,
model_definition=to_model_definition_draft(input.model_definition),
revision_preset_id=input.revision_preset_id,
)
action_result = await self._processors.deployment.add_model_revision.wait_for_complete(
Expand Down
Loading
Loading