add api-version option

This commit is contained in:
David Asamu
2025-07-19 02:55:47 +01:00
parent c16e42e6d5
commit 8d6cd15669
6 changed files with 698 additions and 12 deletions
+25 -5
View File
@@ -153,6 +153,12 @@ OPT_POSTGRES_URI = click.option(
help="Postgres URI to use for the database. Defaults to launching a local database",
)
OPT_API_VERSION = click.option(
"--api-version",
type=str,
help="API server version to use for the base image. If unspecified, the latest version will be used.",
)
@click.group()
@click.version_option(version=__version__, prog_name="LangGraph CLI")
@@ -170,6 +176,7 @@ def cli():
@OPT_DEBUGGER_BASE_URL
@OPT_WATCH
@OPT_POSTGRES_URI
@OPT_API_VERSION
@click.option(
"--image",
type=str,
@@ -203,6 +210,7 @@ def up(
debugger_port: Optional[int],
debugger_base_url: Optional[str],
postgres_uri: Optional[str],
api_version: Optional[str],
image: Optional[str],
base_image: Optional[str],
):
@@ -225,6 +233,7 @@ For production use, requires a license key in env var LANGGRAPH_CLOUD_LICENSE_KE
debugger_port=debugger_port,
debugger_base_url=debugger_base_url,
postgres_uri=postgres_uri,
api_version=api_version,
image=image,
base_image=base_image,
)
@@ -290,6 +299,7 @@ def _build(
config: pathlib.Path,
config_json: dict,
base_image: Optional[str],
api_version: Optional[str],
pull: bool,
tag: str,
passthrough: Sequence[str] = (),
@@ -300,7 +310,7 @@ def _build(
subp_exec(
"docker",
"pull",
langgraph_cli.config.docker_tag(config_json, base_image),
langgraph_cli.config.docker_tag(config_json, base_image, api_version),
verbose=True,
)
)
@@ -314,7 +324,7 @@ def _build(
]
# apply config
stdin, additional_contexts = langgraph_cli.config.config_to_docker(
config, config_json, base_image
config, config_json, base_image, api_version
)
# add additional_contexts
if additional_contexts:
@@ -355,6 +365,7 @@ def _build(
"\n\n \b\nExamples:\n --base-image langchain/langgraph-server:0.2.18 # Pin to a specific patch version"
"\n --base-image langchain/langgraph-server:0.2 # Pin to a minor version (Python)",
)
@OPT_API_VERSION
@click.argument("docker_build_args", nargs=-1, type=click.UNPROCESSED)
@cli.command(
help="📦 Build LangGraph API server Docker image.",
@@ -367,6 +378,7 @@ def build(
config: pathlib.Path,
docker_build_args: Sequence[str],
base_image: Optional[str],
api_version: Optional[str],
pull: bool,
tag: str,
):
@@ -376,7 +388,7 @@ def build(
config_json = langgraph_cli.config.validate_config_file(config)
warn_non_wolfi_distro(config_json)
_build(
runner, set, config, config_json, base_image, pull, tag, docker_build_args
runner, set, config, config_json, base_image, api_version, pull, tag, docker_build_args
)
@@ -456,12 +468,14 @@ tests
"\n\n \b\nExamples:\n --base-image langchain/langgraph-server:0.2.18 # Pin to a specific patch version"
"\n --base-image langchain/langgraph-server:0.2 # Pin to a minor version (Python)",
)
@OPT_API_VERSION
@log_command
def dockerfile(
save_path: str,
config: pathlib.Path,
add_docker_compose: bool,
base_image: Optional[str] = None,
api_version: Optional[str] = None,
) -> None:
save_path = pathlib.Path(save_path).absolute()
secho(f"🔍 Validating configuration at path: {config}", fg="yellow")
@@ -474,6 +488,7 @@ def dockerfile(
config,
config_json,
base_image=base_image,
api_version=api_version,
)
with open(str(save_path), "w", encoding="utf-8") as f:
f.write(dockerfile)
@@ -739,11 +754,12 @@ def prepare_args_and_stdin(
debugger_port: Optional[int] = None,
debugger_base_url: Optional[str] = None,
postgres_uri: Optional[str] = None,
api_version: Optional[str] = None,
# Like "my-tag" (if you already built it locally)
image: Optional[str] = None,
# Like "langchain/langgraphjs-api" or "langchain/langgraph-api
base_image: Optional[str] = None,
) -> tuple[list[str], str]:
):
assert config_path.exists(), f"Config file not found: {config_path}"
# prepare args
stdin = langgraph_cli.docker.compose(
@@ -754,6 +770,7 @@ def prepare_args_and_stdin(
postgres_uri=postgres_uri,
image=image, # Pass image to compose YAML generator
base_image=base_image,
api_version=api_version,
)
args = [
"--project-directory",
@@ -769,6 +786,7 @@ def prepare_args_and_stdin(
config,
watch=watch,
base_image=langgraph_cli.config.default_base_image(config),
api_version=api_version,
image=image,
)
return args, stdin
@@ -787,6 +805,7 @@ def prepare(
debugger_port: Optional[int] = None,
debugger_base_url: Optional[str] = None,
postgres_uri: Optional[str] = None,
api_version: Optional[str] = None,
image: Optional[str] = None,
base_image: Optional[str] = None,
) -> tuple[list[str], str]:
@@ -799,7 +818,7 @@ def prepare(
subp_exec(
"docker",
"pull",
langgraph_cli.config.docker_tag(config_json, base_image),
langgraph_cli.config.docker_tag(config_json, base_image, api_version),
verbose=verbose,
)
)
@@ -814,6 +833,7 @@ def prepare(
debugger_port=debugger_port,
debugger_base_url=debugger_base_url or f"http://127.0.0.1:{port}",
postgres_uri=postgres_uri,
api_version=api_version,
image=image,
base_image=base_image,
)
+25 -7
View File
@@ -1133,6 +1133,7 @@ def python_config_to_docker(
config_path: pathlib.Path,
config: Config,
base_image: str,
api_version: Optional[str] = None,
) -> tuple[str, dict[str, str]]:
"""Generate a Dockerfile from the configuration."""
pip_installer = config.get("pip_installer", "auto")
@@ -1282,7 +1283,7 @@ ADD {relpath} /deps/{name}
"# -- End of JS dependencies install --",
]
)
image_str = docker_tag(config, base_image)
image_str = docker_tag(config, base_image, api_version)
docker_file_contents = [
f"FROM {image_str}",
"",
@@ -1320,10 +1321,11 @@ def node_config_to_docker(
config_path: pathlib.Path,
config: Config,
base_image: str,
api_version: Optional[str] = None,
) -> tuple[str, dict[str, str]]:
faux_path = f"/deps/{config_path.parent.name}"
install_cmd = _get_node_pm_install_cmd(config_path, config)
image_str = docker_tag(config, base_image)
image_str = docker_tag(config, base_image, api_version)
env_vars: list[str] = []
@@ -1379,6 +1381,7 @@ def default_base_image(config: Config) -> str:
def docker_tag(
config: Config,
base_image: Optional[str] = None,
api_version: Optional[str] = None,
) -> str:
base_image = base_image or default_base_image(config)
@@ -1391,28 +1394,43 @@ def docker_tag(
if "/langgraph-server" in base_image:
return f"{base_image}-py{config['python_version']}"
# Build the standard tag format
language, version = None, None
if config.get("node_version") and not config.get("python_version"):
return f"{base_image}:{config['node_version']}{distro_tag}"
return f"{base_image}:{config['python_version']}{distro_tag}"
language, version = "node", config["node_version"]
else:
language, version = "py", config["python_version"]
lang_distro_tag = f"{version}{distro_tag}"
# Prepend API version if provided
if api_version:
full_tag = f"{api_version}-{language}{lang_distro_tag}"
else:
full_tag = lang_distro_tag
return f"{base_image}:{full_tag}"
def config_to_docker(
config_path: pathlib.Path,
config: Config,
base_image: Optional[str] = None,
api_version: Optional[str] = None,
) -> tuple[str, dict[str, str]]:
base_image = base_image or default_base_image(config)
if config.get("node_version") and not config.get("python_version"):
return node_config_to_docker(config_path, config, base_image)
return node_config_to_docker(config_path, config, base_image, api_version)
return python_config_to_docker(config_path, config, base_image)
return python_config_to_docker(config_path, config, base_image, api_version)
def config_to_compose(
config_path: pathlib.Path,
config: Config,
base_image: Optional[str] = None,
api_version: Optional[str] = None,
image: Optional[str] = None,
watch: bool = False,
) -> str:
@@ -1449,7 +1467,7 @@ def config_to_compose(
else:
dockerfile, additional_contexts = config_to_docker(
config_path, config, base_image
config_path, config, base_image, api_version
)
additional_contexts_str = "\n".join(
+4
View File
@@ -147,6 +147,8 @@ def compose_as_dict(
image: Optional[str] = None,
# Base image to use for the LangGraph API server
base_image: Optional[str] = None,
# API version of the base image
api_version: Optional[str] = None,
) -> dict:
"""Create a docker compose file as a dictionary in YML style."""
if postgres_uri is None:
@@ -252,6 +254,7 @@ def compose(
postgres_uri: Optional[str] = None,
image: Optional[str] = None,
base_image: Optional[str] = None,
api_version: Optional[str] = None,
) -> str:
"""Create a docker compose file as a string."""
compose_content = compose_as_dict(
@@ -262,6 +265,7 @@ def compose(
postgres_uri=postgres_uri,
image=image,
base_image=base_image,
api_version=api_version,
)
compose_str = dict_to_yaml(compose_content)
return compose_str