mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-10 03:37:51 +02:00
add support for image_distro in config file
This commit is contained in:
@@ -165,6 +165,13 @@ def generate_schema():
|
||||
if "python_version" in python_schema["properties"]:
|
||||
python_schema["properties"]["python_version"]["enum"] = ["3.11", "3.12"]
|
||||
|
||||
# Add enum constraint for image_distro
|
||||
if "image_distro" in python_schema["properties"]:
|
||||
python_schema["properties"]["image_distro"]["anyOf"] = [
|
||||
{"type": "string", "enum": ["debian", "wolfi"]},
|
||||
{"type": "null"},
|
||||
]
|
||||
|
||||
# Create Node.js schema with node_version
|
||||
node_schema = {
|
||||
"type": "object",
|
||||
@@ -184,6 +191,13 @@ def generate_schema():
|
||||
{"type": "null"},
|
||||
]
|
||||
|
||||
# Add enum constraint for image_distro
|
||||
if "image_distro" in node_schema["properties"]:
|
||||
node_schema["properties"]["image_distro"]["anyOf"] = [
|
||||
{"type": "string", "enum": ["debian", "wolfi"]},
|
||||
{"type": "null"},
|
||||
]
|
||||
|
||||
# Replace the Config schema with a oneOf constraint
|
||||
config_schema["oneOf"] = [python_schema, node_schema]
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ DEFAULT_NODE_VERSION = "20"
|
||||
MIN_PYTHON_VERSION = "3.11"
|
||||
DEFAULT_PYTHON_VERSION = "3.11"
|
||||
|
||||
DEFAULT_IMAGE_DISTRO = "debian"
|
||||
|
||||
|
||||
class TTLConfig(TypedDict, total=False):
|
||||
"""Configuration for TTL (time-to-live) behavior in the store."""
|
||||
@@ -367,6 +369,12 @@ class Config(TypedDict, total=False):
|
||||
|
||||
Defaults to langchain/langgraph-api or langchain/langgraphjs-api."""
|
||||
|
||||
image_distro: Optional[str]
|
||||
"""Optional. Linux distribution for the base image.
|
||||
|
||||
Must be either 'debian' or 'wolfi'. If omitted, defaults to 'debian'.
|
||||
"""
|
||||
|
||||
pip_config_file: Optional[str]
|
||||
"""Optional. Path to a pip config file (e.g., "/etc/pip.conf" or "pip.ini") for controlling
|
||||
package installation (custom indices, credentials, etc.).
|
||||
@@ -517,12 +525,15 @@ def validate_config(config: Config) -> Config:
|
||||
"python_version", DEFAULT_PYTHON_VERSION if some_python else None
|
||||
)
|
||||
|
||||
image_distro = config.get("image_distro", DEFAULT_IMAGE_DISTRO)
|
||||
|
||||
config = {
|
||||
"node_version": node_version,
|
||||
"python_version": python_version,
|
||||
"pip_config_file": config.get("pip_config_file"),
|
||||
"_INTERNAL_docker_tag": config.get("_INTERNAL_docker_tag"),
|
||||
"base_image": config.get("base_image"),
|
||||
"image_distro": image_distro,
|
||||
"dependencies": config.get("dependencies", []),
|
||||
"dockerfile_lines": config.get("dockerfile_lines", []),
|
||||
"graphs": config.get("graphs", {}),
|
||||
@@ -576,6 +587,14 @@ def validate_config(config: Config) -> Config:
|
||||
"Add at least one graph to 'graphs' dictionary."
|
||||
)
|
||||
|
||||
# Validate image_distro config
|
||||
if image_distro := config.get("image_distro"):
|
||||
if image_distro not in ["debian", "wolfi"]:
|
||||
raise click.UsageError(
|
||||
f"Invalid image_distro: '{image_distro}'. "
|
||||
"Must be either 'debian' or 'wolfi'."
|
||||
)
|
||||
|
||||
# Validate auth config
|
||||
if auth_conf := config.get("auth"):
|
||||
if "path" in auth_conf:
|
||||
@@ -1306,6 +1325,7 @@ def docker_tag(
|
||||
base_image: Optional[str] = None,
|
||||
) -> str:
|
||||
base_image = base_image or default_base_image(config)
|
||||
wolfi_tag = "-wolfi" if config.get("image_distro") == "wolfi" else ""
|
||||
if config.get("_INTERNAL_docker_tag"):
|
||||
return f"{base_image}:{config['_INTERNAL_docker_tag']}"
|
||||
|
||||
@@ -1313,8 +1333,8 @@ def docker_tag(
|
||||
return f"{base_image}-py{config['python_version']}"
|
||||
|
||||
if config.get("node_version") and not config.get("python_version"):
|
||||
return f"{base_image}:{config['node_version']}"
|
||||
return f"{base_image}:{config['python_version']}"
|
||||
return f"{base_image}:{config['node_version']}{wolfi_tag}"
|
||||
return f"{base_image}:{config['python_version']}{wolfi_tag}"
|
||||
|
||||
|
||||
def config_to_docker(
|
||||
|
||||
@@ -34,6 +34,7 @@ def test_validate_config():
|
||||
"python_version": "3.11",
|
||||
"node_version": None,
|
||||
"pip_config_file": None,
|
||||
"image_distro": "debian",
|
||||
"dockerfile_lines": [],
|
||||
"env": {},
|
||||
"store": None,
|
||||
@@ -54,6 +55,7 @@ def test_validate_config():
|
||||
"python_version": "3.12",
|
||||
"node_version": None,
|
||||
"pip_config_file": "pipconfig.txt",
|
||||
"image_distro": "debian",
|
||||
"dockerfile_lines": ["ARG meow"],
|
||||
"dependencies": [".", "langchain"],
|
||||
"graphs": {
|
||||
@@ -120,18 +122,90 @@ def test_validate_config():
|
||||
}
|
||||
)
|
||||
assert config["python_version"] == "3.12-slim"
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match="Invalid http.app format",
|
||||
):
|
||||
with pytest.raises(ValueError, match="Invalid http.app format"):
|
||||
validate_config({
|
||||
"python_version": "3.12",
|
||||
"dependencies": ["."],
|
||||
"graphs": {"agent": "./agent.py:graph"},
|
||||
"http": {"app": "../../examples/my_app.py"},
|
||||
})
|
||||
|
||||
|
||||
def test_validate_config_image_distro():
|
||||
"""Test validation of image_distro field."""
|
||||
# Valid image_distro values should work
|
||||
config = validate_config(
|
||||
{
|
||||
"python_version": "3.11",
|
||||
"dependencies": ["."],
|
||||
"graphs": {"agent": "./agent.py:graph"},
|
||||
"image_distro": "debian",
|
||||
}
|
||||
)
|
||||
assert config["image_distro"] == "debian"
|
||||
|
||||
config = validate_config(
|
||||
{
|
||||
"python_version": "3.11",
|
||||
"dependencies": ["."],
|
||||
"graphs": {"agent": "./agent.py:graph"},
|
||||
"image_distro": "wolfi",
|
||||
}
|
||||
)
|
||||
assert config["image_distro"] == "wolfi"
|
||||
|
||||
# Missing image_distro should default to 'debian'
|
||||
config = validate_config(
|
||||
{
|
||||
"python_version": "3.11",
|
||||
"dependencies": ["."],
|
||||
"graphs": {"agent": "./agent.py:graph"},
|
||||
}
|
||||
)
|
||||
assert config["image_distro"] == "debian"
|
||||
|
||||
# Invalid image_distro values should raise error
|
||||
with pytest.raises(click.UsageError) as exc_info:
|
||||
validate_config(
|
||||
{
|
||||
"python_version": "3.12",
|
||||
"python_version": "3.11",
|
||||
"dependencies": ["."],
|
||||
"graphs": {"agent": "./agent.py:graph"},
|
||||
"http": {"app": "../../examples/my_app.py"},
|
||||
"image_distro": "ubuntu",
|
||||
}
|
||||
)
|
||||
assert "Invalid image_distro: 'ubuntu'" in str(exc_info.value)
|
||||
assert "Must be either 'debian' or 'wolfi'" in str(exc_info.value)
|
||||
|
||||
with pytest.raises(click.UsageError) as exc_info:
|
||||
validate_config(
|
||||
{
|
||||
"python_version": "3.11",
|
||||
"dependencies": ["."],
|
||||
"graphs": {"agent": "./agent.py:graph"},
|
||||
"image_distro": "alpine",
|
||||
}
|
||||
)
|
||||
assert "Invalid image_distro: 'alpine'" in str(exc_info.value)
|
||||
|
||||
# Test with Node.js config too
|
||||
config = validate_config(
|
||||
{
|
||||
"node_version": "20",
|
||||
"graphs": {"agent": "./agent.js:graph"},
|
||||
"image_distro": "wolfi",
|
||||
}
|
||||
)
|
||||
assert config["image_distro"] == "wolfi"
|
||||
|
||||
# Test Node.js config with default
|
||||
config = validate_config(
|
||||
{
|
||||
"node_version": "20",
|
||||
"graphs": {"agent": "./agent.js:graph"},
|
||||
}
|
||||
)
|
||||
assert config["image_distro"] == "debian"
|
||||
|
||||
|
||||
def test_validate_config_file():
|
||||
|
||||
Reference in New Issue
Block a user