diff --git a/libs/cli/generate_schema.py b/libs/cli/generate_schema.py index 1d557035c..8a2e3718d 100644 --- a/libs/cli/generate_schema.py +++ b/libs/cli/generate_schema.py @@ -15,12 +15,15 @@ import msgspec from langgraph_cli.config import ( AuthConfig, + CheckpointerConfig, Config, CorsConfig, HttpConfig, IndexConfig, SecurityConfig, StoreConfig, + ThreadTTLConfig, + TTLConfig, ) @@ -106,6 +109,9 @@ def add_descriptions_to_schema(schema, cls): SecurityConfig, HttpConfig, CorsConfig, + ThreadTTLConfig, + CheckpointerConfig, + TTLConfig, ]: if potential_cls.__name__ == def_name: add_descriptions_to_schema(def_schema, potential_cls) diff --git a/libs/cli/langgraph_cli/config.py b/libs/cli/langgraph_cli/config.py index 39ba9c23e..f1308c989 100644 --- a/libs/cli/langgraph_cli/config.py +++ b/libs/cli/langgraph_cli/config.py @@ -3,7 +3,7 @@ import os import pathlib import textwrap from collections import Counter -from typing import Any, NamedTuple, Optional, TypedDict, Union +from typing import Any, Literal, NamedTuple, Optional, TypedDict, Union import click @@ -111,6 +111,36 @@ class StoreConfig(TypedDict, total=False): """ +class ThreadTTLConfig(TypedDict, total=False): + """Configure a default TTL for checkpointed data within threads.""" + + strategy: Literal["delete"] + """Strategy to use for deleting checkpointed data. + + Choices: + - "delete": Delete all checkpoints for a thread after TTL expires. + """ + default_ttl: Optional[float] + """Default TTL (time-to-live) in minutes for checkpointed data.""" + sweep_interval_minutes: Optional[int] + """Interval in minutes between sweep iterations. + If omitted, a default interval will be used (typically ~ 5 minutes).""" + + +class CheckpointerConfig(TypedDict, total=False): + """Configuration for the built-in checkpointer, which handles checkpointing of state. + + If omitted, no checkpointer is set up (the object store will still be present, however). + """ + + ttl: Optional[ThreadTTLConfig] + """Optional. Defines the TTL (time-to-live) behavior configuration. + + If provided, the checkpointer will apply TTL settings according to the configuration. + If omitted, no TTL behavior is configured. + """ + + class SecurityConfig(TypedDict, total=False): """Configuration for OpenAPI security definitions and requirements. @@ -229,7 +259,7 @@ class CorsConfig(TypedDict, total=False): allow_origin_regex: str """Optional. A regex pattern for matching allowed origins, used if you have dynamic subdomains. - Example: "^https://.*\.mycompany\.com$" + Example: "^https://.*\\.mycompany\\.com$" """ expose_headers: list[str] """Optional. List of headers that browsers are allowed to read from the response in cross-origin contexts.""" @@ -355,6 +385,12 @@ class Config(TypedDict, total=False): If omitted, no vector index is set up (the object store will still be present, however). """ + checkpointer: Optional[CheckpointerConfig] + """Optional. Configuration for the built-in checkpointer, which handles checkpointing of state. + + If omitted, no checkpointer is set up (the object store will still be present, however). + """ + auth: Optional[AuthConfig] """Optional. Custom authentication config, including the path to your Python auth logic and the OpenAPI security definitions it uses. @@ -404,6 +440,7 @@ def validate_config(config: Config) -> Config: "store": config.get("store"), "auth": config.get("auth"), "http": config.get("http"), + "checkpointer": config.get("checkpointer"), "ui": config.get("ui"), "ui_config": config.get("ui_config"), } @@ -418,6 +455,7 @@ def validate_config(config: Config) -> Config: "store": config.get("store"), "auth": config.get("auth"), "http": config.get("http"), + "checkpointer": config.get("checkpointer"), "ui": config.get("ui"), "ui_config": config.get("ui_config"), } @@ -981,6 +1019,11 @@ ADD {relpath} /deps/{name} if (http_config := config.get("http")) is not None: env_vars.append(f"ENV LANGGRAPH_HTTP='{json.dumps(http_config)}'") + if (checkpointer_config := config.get("checkpointer")) is not None: + env_vars.append( + f"ENV LANGGRAPH_CHECKPOINTER='{json.dumps(checkpointer_config)}'" + ) + graphs = config["graphs"] env_vars.append(f"ENV LANGSERVE_GRAPHS='{json.dumps(graphs)}'") @@ -1087,6 +1130,10 @@ ENV LANGGRAPH_AUTH='{json.dumps(auth_config)}' if (http_config := config.get("http")) is not None: env_additional_config += f""" ENV LANGGRAPH_HTTP='{json.dumps(http_config)}' +""" + if (checkpointer_config := config.get("checkpointer")) is not None: + env_additional_config += f""" +ENV LANGGRAPH_CHECKPOINTER='{json.dumps(checkpointer_config)}' """ return ( diff --git a/libs/cli/pyproject.toml b/libs/cli/pyproject.toml index 1b1da4e97..363fc2a01 100644 --- a/libs/cli/pyproject.toml +++ b/libs/cli/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph-cli" -version = "0.1.82" +version = "0.1.83" description = "CLI for interacting with LangGraph API" authors = [] license = "MIT" diff --git a/libs/cli/schemas/schema.json b/libs/cli/schemas/schema.json index 3cca859b2..015f0e209 100644 --- a/libs/cli/schemas/schema.json +++ b/libs/cli/schemas/schema.json @@ -40,6 +40,17 @@ ], "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" }, + "checkpointer": { + "anyOf": [ + { + "$ref": "#/$defs/CheckpointerConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in checkpointer, which handles checkpointing of state.\n\nIf omitted, no checkpointer is set up (the object store will still be present, however).\n" + }, "dependencies": { "type": "array", "items": { @@ -145,6 +156,17 @@ ], "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" }, + "checkpointer": { + "anyOf": [ + { + "$ref": "#/$defs/CheckpointerConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in checkpointer, which handles checkpointing of state.\n\nIf omitted, no checkpointer is set up (the object store will still be present, however).\n" + }, "dependencies": { "type": "array", "items": { @@ -291,6 +313,61 @@ }, "required": [] }, + "CheckpointerConfig": { + "title": "CheckpointerConfig", + "description": "Configuration for the built-in checkpointer, which handles checkpointing of state.\n\nIf omitted, no checkpointer is set up (the object store will still be present, however).", + "type": "object", + "properties": { + "ttl": { + "anyOf": [ + { + "$ref": "#/$defs/ThreadTTLConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines the TTL (time-to-live) behavior configuration.\n\nIf provided, the checkpointer will apply TTL settings according to the configuration.\nIf omitted, no TTL behavior is configured.\n" + } + }, + "required": [] + }, + "ThreadTTLConfig": { + "title": "ThreadTTLConfig", + "description": "Configure a default TTL for checkpointed data within threads.", + "type": "object", + "properties": { + "default_ttl": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Default TTL (time-to-live) in minutes for checkpointed data." + }, + "strategy": { + "enum": [ + "delete" + ], + "description": "Strategy to use for deleting checkpointed data.\n" + }, + "sweep_interval_minutes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Interval in minutes between sweep iterations.\nIf omitted, a default interval will be used (typically ~ 5 minutes)." + } + }, + "required": [] + }, "HttpConfig": { "title": "HttpConfig", "description": "Configuration for the built-in HTTP server that powers your deployment's routes and endpoints.", @@ -455,10 +532,12 @@ { "type": "null" } - ] + ], + "description": "Optional. Default TTL (time-to-live) in minutes for new items.\n\nIf provided, all new items will have this TTL unless explicitly overridden.\nIf omitted, items will have no TTL by default.\n" }, "refresh_on_read": { - "type": "boolean" + "type": "boolean", + "description": "Default behavior for refreshing TTLs on read operations (GET and SEARCH).\n\nIf True, TTLs will be refreshed on read operations (get/search) by default.\nThis can be overridden per-operation by explicitly setting refresh_ttl.\nDefaults to True if not configured.\n" }, "sweep_interval_minutes": { "anyOf": [ @@ -468,7 +547,8 @@ { "type": "null" } - ] + ], + "description": "Optional. Interval in minutes between TTL sweep iterations.\n\nIf provided, the store will periodically delete expired items based on the TTL.\nIf omitted, no automatic sweeping will occur.\n" } }, "required": [] diff --git a/libs/cli/schemas/schema.v0.json b/libs/cli/schemas/schema.v0.json index 3cca859b2..015f0e209 100644 --- a/libs/cli/schemas/schema.v0.json +++ b/libs/cli/schemas/schema.v0.json @@ -40,6 +40,17 @@ ], "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" }, + "checkpointer": { + "anyOf": [ + { + "$ref": "#/$defs/CheckpointerConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in checkpointer, which handles checkpointing of state.\n\nIf omitted, no checkpointer is set up (the object store will still be present, however).\n" + }, "dependencies": { "type": "array", "items": { @@ -145,6 +156,17 @@ ], "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" }, + "checkpointer": { + "anyOf": [ + { + "$ref": "#/$defs/CheckpointerConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in checkpointer, which handles checkpointing of state.\n\nIf omitted, no checkpointer is set up (the object store will still be present, however).\n" + }, "dependencies": { "type": "array", "items": { @@ -291,6 +313,61 @@ }, "required": [] }, + "CheckpointerConfig": { + "title": "CheckpointerConfig", + "description": "Configuration for the built-in checkpointer, which handles checkpointing of state.\n\nIf omitted, no checkpointer is set up (the object store will still be present, however).", + "type": "object", + "properties": { + "ttl": { + "anyOf": [ + { + "$ref": "#/$defs/ThreadTTLConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines the TTL (time-to-live) behavior configuration.\n\nIf provided, the checkpointer will apply TTL settings according to the configuration.\nIf omitted, no TTL behavior is configured.\n" + } + }, + "required": [] + }, + "ThreadTTLConfig": { + "title": "ThreadTTLConfig", + "description": "Configure a default TTL for checkpointed data within threads.", + "type": "object", + "properties": { + "default_ttl": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Default TTL (time-to-live) in minutes for checkpointed data." + }, + "strategy": { + "enum": [ + "delete" + ], + "description": "Strategy to use for deleting checkpointed data.\n" + }, + "sweep_interval_minutes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Interval in minutes between sweep iterations.\nIf omitted, a default interval will be used (typically ~ 5 minutes)." + } + }, + "required": [] + }, "HttpConfig": { "title": "HttpConfig", "description": "Configuration for the built-in HTTP server that powers your deployment's routes and endpoints.", @@ -455,10 +532,12 @@ { "type": "null" } - ] + ], + "description": "Optional. Default TTL (time-to-live) in minutes for new items.\n\nIf provided, all new items will have this TTL unless explicitly overridden.\nIf omitted, items will have no TTL by default.\n" }, "refresh_on_read": { - "type": "boolean" + "type": "boolean", + "description": "Default behavior for refreshing TTLs on read operations (GET and SEARCH).\n\nIf True, TTLs will be refreshed on read operations (get/search) by default.\nThis can be overridden per-operation by explicitly setting refresh_ttl.\nDefaults to True if not configured.\n" }, "sweep_interval_minutes": { "anyOf": [ @@ -468,7 +547,8 @@ { "type": "null" } - ] + ], + "description": "Optional. Interval in minutes between TTL sweep iterations.\n\nIf provided, the store will periodically delete expired items based on the TTL.\nIf omitted, no automatic sweeping will occur.\n" } }, "required": [] diff --git a/libs/cli/tests/unit_tests/test_config.py b/libs/cli/tests/unit_tests/test_config.py index 981b481b4..b205b1204 100644 --- a/libs/cli/tests/unit_tests/test_config.py +++ b/libs/cli/tests/unit_tests/test_config.py @@ -32,6 +32,7 @@ def test_validate_config(): "env": {}, "store": None, "auth": None, + "checkpointer": None, "http": None, "ui": None, "ui_config": None, @@ -53,6 +54,7 @@ def test_validate_config(): "env": env, "store": None, "auth": None, + "checkpointer": None, "http": None, "ui": None, "ui_config": None,