diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 154aaff23..9bed24785 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,6 +114,42 @@ jobs: - name: Run check_sdk_methods script run: python .github/scripts/check_sdk_methods.py + check-schema: + needs: changes + if: needs.changes.outputs.python == 'true' + name: "Check CLI schema hasn't changed #${{ matrix.python-version }}" + runs-on: ubuntu-latest + strategy: + matrix: + python-version: + - "3.11" + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }} + uses: "./.github/actions/poetry_setup" + with: + python-version: "3.11" + poetry-version: ${{ env.POETRY_VERSION }} + cache-key: schema-check-cli + - name: Install CLI dependencies + run: | + cd libs/cli + poetry install + - name: Generate schema and check for changes + run: | + cd libs/cli + # Create a temporary copy of the current schema + cp schemas/schema.json schemas/schema.current.json + # Generate new schema + poetry run python generate_schema.py + # Compare the new schema with the original + if ! diff -q schemas/schema.json schemas/schema.current.json > /dev/null; then + echo "Error: Langgraph.json configuration schema has changed. Please run 'poetry run python generate_schema.py' in the libs/cli directory and commit the changes." + diff schemas/schema.json schemas/schema.current.json + exit 1 + fi + echo "Schema check passed - no changes detected" + integration-test: needs: changes if: needs.changes.outputs.python == 'true' @@ -180,6 +216,8 @@ jobs: test, test-langgraph, test-scheduler-kafka, + check-sdk-methods, + check-schema, integration-test, test-js, ] diff --git a/libs/cli/generate_schema.py b/libs/cli/generate_schema.py new file mode 100644 index 000000000..1d557035c --- /dev/null +++ b/libs/cli/generate_schema.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 +""" +Script to generate a JSON schema for the langgraph-cli Config class. + +This script creates a schema.json file that can be referenced in langgraph.json files +to provide IDE autocompletion and validation. +""" + +import inspect +import json +import textwrap +from pathlib import Path + +import msgspec + +from langgraph_cli.config import ( + AuthConfig, + Config, + CorsConfig, + HttpConfig, + IndexConfig, + SecurityConfig, + StoreConfig, +) + + +def add_descriptions_to_schema(schema, cls): + """Add docstring descriptions to the schema properties.""" + if schema.get("description"): + schema["description"] = inspect.cleandoc(schema["description"]) + elif class_doc := inspect.getdoc(cls): + schema["description"] = inspect.cleandoc(class_doc) + # Get attribute docstrings from the class + attr_docs = {} + + # Also check class annotations for docstrings + source_lines = inspect.getsourcelines(cls)[0] + current_attr = None + docstring_lines = [] + + for line in source_lines: + line = line.strip() + + # Check for attribute definition (TypedDict style) + if ":" in line and not line.startswith("#") and not line.startswith('"""'): + parts = line.split(":", 1) + if len(parts) == 2 and parts[0].strip().isidentifier(): + # If we were collecting a docstring, save it for the previous attribute + if current_attr and docstring_lines: + attr_docs[current_attr] = "\n".join(docstring_lines).strip('"') + docstring_lines = [] + + current_attr = parts[0].strip() + + # Check for docstring after attribute + elif line.startswith('"""') and current_attr: + # Start or end of a docstring + if len(line) > 3 and line.endswith('"""'): + # Single line docstring + attr_docs[current_attr] = line.strip('"') + current_attr = None + elif docstring_lines: + # End of multi-line docstring + docstring_lines.append(line.rstrip('"')) + attr_docs[current_attr] = "\n".join(docstring_lines).strip('"') + docstring_lines = [] + current_attr = None + else: + # Start of multi-line docstring + docstring_lines.append(line.lstrip('"')) + + # Continue multi-line docstring + elif docstring_lines and current_attr: + docstring_lines.append(line.strip('"')) + + # Add the last docstring if there is one + if current_attr and docstring_lines: + attr_docs[current_attr] = "\n".join(docstring_lines).strip('"') + + # Add descriptions to properties + if "properties" in schema: + for prop_name, prop_schema in schema["properties"].items(): + # First try to get from attribute docstrings + if prop_name in attr_docs and "description" not in prop_schema: + prop_schema["description"] = textwrap.dedent(attr_docs[prop_name]) + # Fall back to class docstring parsing + elif class_doc: + for line in class_doc.split("\n"): + if line.strip().startswith( + f"{prop_name}:" + ) or line.strip().startswith(f'"{prop_name}"'): + description = line.split(":", 1)[1].strip() + if description and "description" not in prop_schema: + prop_schema["description"] = description + break + + # Recursively process nested definitions + if "$defs" in schema: + for def_name, def_schema in schema["$defs"].items(): + # Find the class that corresponds to this definition + for potential_cls in [ + Config, + StoreConfig, + IndexConfig, + AuthConfig, + SecurityConfig, + HttpConfig, + CorsConfig, + ]: + if potential_cls.__name__ == def_name: + add_descriptions_to_schema(def_schema, potential_cls) + break + + return schema + + +def generate_schema(): + """Generate a JSON schema for the Config class using msgspec.""" + # Generate the basic schema + schema = msgspec.json.schema(Config) + + # Add title and description + schema["title"] = "LangGraph CLI Configuration" + schema["description"] = "Configuration schema for langgraph-cli" + + # Add docstring descriptions + schema = add_descriptions_to_schema(schema, Config) + + # Add constraint that only one of python_version or node_version should be specified + config_schema = schema["$defs"]["Config"] + + # Create two subschemas: one with python_version and one with node_version + # Define properties specific to Python projects + python_specific_props = ["python_version", "pip_config_file"] + # Define properties specific to Node.js projects + node_specific_props = ["node_version"] + # Define properties common to both project types + common_props = [ + k + for k in config_schema["properties"] + if k not in python_specific_props and k not in node_specific_props + ] + + # Create Python schema with python_version and pip_config_file + python_schema = { + "type": "object", + "properties": { + # Include Python-specific properties + **{k: config_schema["properties"][k].copy() for k in python_specific_props}, + # Include common properties + **{k: config_schema["properties"][k].copy() for k in common_props}, + }, + "required": ["dependencies", "graphs"], + } + + # Add enum constraint for python_version + if "python_version" in python_schema["properties"]: + python_schema["properties"]["python_version"]["enum"] = ["3.11", "3.12"] + + # Create Node.js schema with node_version + node_schema = { + "type": "object", + "properties": { + # Include Node-specific properties + **{k: config_schema["properties"][k].copy() for k in node_specific_props}, + # Include common properties + **{k: config_schema["properties"][k].copy() for k in common_props}, + }, + "required": ["node_version", "graphs"], + } + + # Add enum constraint for node_version + if "node_version" in node_schema["properties"]: + node_schema["properties"]["node_version"]["anyOf"] = [ + {"type": "string", "enum": ["20"]}, + {"type": "null"}, + ] + + # Replace the Config schema with a oneOf constraint + config_schema["oneOf"] = [python_schema, node_schema] + + # Remove the properties field as it's now defined in the oneOf subschemas + if "properties" in config_schema: + del config_schema["properties"] + + return schema + + +def main(): + """Generate the schema and write it to a file.""" + schema = generate_schema() + + # Add versioning to the schema + import importlib.metadata + + try: + version = importlib.metadata.version("langgraph_cli").split(".") + schema_version = f"v{version[0]}" + except importlib.metadata.PackageNotFoundError: + schema_version = "v1" + + # Add version to schema + schema["version"] = schema_version + + config_dir = Path(__file__).parent / "schemas" + + # Create versioned schema file + versioned_path = config_dir / f"schema.{schema_version}.json" + with open(versioned_path, "w") as f: + json.dump(schema, f, indent=2) + + # Also create a latest version + latest_path = config_dir / "schema.json" + with open(latest_path, "w") as f: + json.dump(schema, f, indent=2) + + print(f"Schema written to {versioned_path} and {latest_path}") + print( + f"You can now add '$schema: https://raw.githubusercontent.com/langchain-ai/langgraph/refs/heads/main/libs/cli/schemas/schema.json'" + f" or '$schema: https://raw.githubusercontent.com/langchain-ai/langgraph/refs/heads/main/libs/cli/schemas/schema.{schema_version}.json'" + " to your langgraph.json files" + ) + + +if __name__ == "__main__": + main() diff --git a/libs/cli/langgraph_cli/config.py b/libs/cli/langgraph_cli/config.py index 7fbe57056..2b7e4bbcc 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 NamedTuple, Optional, TypedDict, Union +from typing import Any, NamedTuple, Optional, TypedDict, Union import click @@ -12,12 +12,18 @@ MIN_PYTHON_VERSION = "3.11" class IndexConfig(TypedDict, total=False): - """Configuration for indexing documents for semantic search in the store.""" + """Configuration for indexing documents for semantic search in the store. + + This governs how text is converted into embeddings and stored for vector-based lookups. + """ dims: int - """Number of dimensions in the embedding vectors. + """Required. Dimensionality of the embedding vectors you will store. - Common embedding models have the following dimensions: + Must match the output dimension of your selected embedding model or custom embed function. + If mismatched, you will likely encounter shape/size errors when inserting or querying vectors. + + Common embedding model output dimensions: - openai:text-embedding-3-large: 3072 - openai:text-embedding-3-small: 1536 - openai:text-embedding-ada-002: 1536 @@ -28,42 +34,123 @@ class IndexConfig(TypedDict, total=False): """ embed: str - """Optional model (string) to generate embeddings from text or path to model or function. + """Required. Identifier or reference to the embedding model or a custom embedding function. - Examples: + The format can vary: + - ":" for recognized providers (e.g., "openai:text-embedding-3-large") + - "path/to/module.py:function_name" for your own local embedding function + - "my_custom_embed" if it's a known alias in your system + + Examples: - "openai:text-embedding-3-large" - "cohere:embed-multilingual-v3.0" - - "src/app.py:embeddings + - "src/app.py:embeddings" + + Note: Must return embeddings of dimension `dims`. """ fields: Optional[list[str]] - """Fields to extract text from for embedding generation. + """Optional. List of JSON fields to extract before generating embeddings. - Defaults to the root ["$"], which embeds the json object as a whole. + Defaults to ["$"], which means the entire JSON object is embedded as one piece of text. + If you provide multiple fields (e.g. ["title", "content"]), each is extracted and embedded separately, + often saving token usage if you only care about certain parts of the data. + + Example: + fields=["title", "abstract", "author.biography"] """ class StoreConfig(TypedDict, total=False): - embed: Optional[IndexConfig] - """Configuration for vector embeddings in store.""" + """Configuration for the built-in long-term memory store. + + This store can optionally perform semantic search. If you omit `index`, + the store will just handle traditional (non-embedded) data without vector lookups. + """ + + index: Optional[IndexConfig] + """Optional. Defines the vector-based semantic search configuration. + + If provided, the store will: + - Generate embeddings according to `index.embed` + - Enforce the embedding dimension given by `index.dims` + - Embed only specified JSON fields (if any) from `index.fields` + + If omitted, no vector index is initialized. + """ class SecurityConfig(TypedDict, total=False): - securitySchemes: dict - security: list + """Configuration for OpenAPI security definitions and requirements. + + Useful for specifying global or path-level authentication and authorization flows + (e.g., OAuth2, API key headers, etc.). + """ + + securitySchemes: dict[str, dict[str, Any]] + """Required. Dict describing each security scheme recognized by your OpenAPI spec. + + Keys are scheme names (e.g. "OAuth2", "ApiKeyAuth") and values are their definitions. + Example: + { + "OAuth2": { + "type": "oauth2", + "flows": { + "password": { + "tokenUrl": "/token", + "scopes": {"read": "Read data", "write": "Write data"} + } + } + } + } + """ + security: list[dict[str, list[str]]] + """Optional. Global security requirements across all endpoints. + + Each element in the list maps a security scheme (e.g. "OAuth2") to a list of scopes (e.g. ["read", "write"]). + Example: + [ + {"OAuth2": ["read", "write"]}, + {"ApiKeyAuth": []} + ] + """ # path => {method => security} - paths: dict[str, dict[str, list]] + paths: dict[str, dict[str, list[dict[str, list[str]]]]] + """Optional. Path-specific security overrides. + + Keys are path templates (e.g., "/items/{item_id}"), mapping to: + - Keys that are HTTP methods (e.g., "GET", "POST"), + - Values are lists of security definitions (just like `security`) for that method. + + Example: + { + "/private_data": { + "GET": [{"OAuth2": ["read"]}], + "POST": [{"OAuth2": ["write"]}] + } + } + """ class AuthConfig(TypedDict, total=False): - path: str - """Path to the authentication function in a Python file.""" - disable_studio_auth: bool - """Whether to disable auth when connecting from the LangSmith Studio.""" - openapi: SecurityConfig - """The schema to use for updating the openapi spec. + """Configuration for custom authentication logic and how it integrates into the OpenAPI spec.""" - Example: + path: str + """Required. Path to an instance of the Auth() class that implements custom authentication. + + Format: "path/to/file.py:my_auth" + """ + disable_studio_auth: bool + """Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio. + + Defaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header + value is a valid API key for the deployment's workspace. If True, all requests will go through your custom + authentication logic, regardless of origin of the request. + """ + openapi: SecurityConfig + """Required. Detailed security configuration that merges into your deployment's OpenAPI spec. + + Example (OAuth2): { "securitySchemes": { "OAuth2": { @@ -71,88 +158,181 @@ class AuthConfig(TypedDict, total=False): "flows": { "password": { "tokenUrl": "/token", - "scopes": { - "me": "Read information about the current user", - "items": "Access to create and manage items" - } + "scopes": {"me": "Read user info", "items": "Manage items"} } } } }, "security": [ - {"OAuth2": ["me"]} # Default security requirement for all endpoints + {"OAuth2": ["me"]} ] } """ class CorsConfig(TypedDict, total=False): + """Specifies Cross-Origin Resource Sharing (CORS) rules for your server. + + If omitted, defaults are typically very restrictive (often no cross-origin requests). + Configure carefully if you want to allow usage from browsers hosted on other domains. + """ + allow_origins: list[str] + """Optional. List of allowed origins (e.g., "https://example.com"). + + Default is often an empty list (no external origins). + Use "*" only if you trust all origins, as that bypasses most restrictions. + """ allow_methods: list[str] + """Optional. HTTP methods permitted for cross-origin requests (e.g. ["GET", "POST"]). + + Default might be ["GET", "POST", "OPTIONS"] depending on your server framework. + """ allow_headers: list[str] + """Optional. HTTP headers that can be used in cross-origin requests (e.g. ["Content-Type", "Authorization"]).""" allow_credentials: bool + """Optional. If True, cross-origin requests can include credentials (cookies, auth headers). + + Default False to avoid accidentally exposing secured endpoints to untrusted sites. + """ allow_origin_regex: str + """Optional. A regex pattern for matching allowed origins, used if you have dynamic subdomains. + + 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.""" max_age: int + """Optional. How many seconds the browser may cache preflight responses. + + Default might be 600 (10 minutes). Larger values reduce preflight requests but can cause stale configurations. + """ class HttpConfig(TypedDict, total=False): + """Configuration for the built-in HTTP server that powers your deployment's routes and endpoints.""" + app: str - """Import path for a custom Starlette/FastAPI app to mount""" + """Optional. Import path to a custom Starlette/FastAPI application to mount. + + Format: "path/to/module.py:app_var" + If provided, it can override or extend the default routes. + """ disable_assistants: bool - """Disable /assistants routes""" + """Optional. If True, /assistants routes are removed from the server. + + Default is False (meaning /assistants is enabled). + """ disable_threads: bool - """Disable /threads routes""" + """Optional. If True, /threads routes are removed. + + Default is False. + """ disable_runs: bool - """Disable /runs routes""" + """Optional. If True, /runs routes are removed. + + Default is False. + """ disable_store: bool - """Disable /store routes""" + """Optional. If True, /store routes are removed, disabling direct store interactions via HTTP. + + Default is False. + """ disable_meta: bool - """Disable /ok, /info, /metrics, and /docs routes""" + """Optional. If True, all meta endpoints (/ok, /info, /metrics, /docs) are disabled. + + Default is False. + """ cors: Optional[CorsConfig] - """Cross-Origin Resource Sharing (CORS) configuration""" + """Optional. Defines CORS restrictions. If omitted, no special rules are set and + cross-origin behavior depends on default server settings. + """ class Config(TypedDict, total=False): - """Configuration for langgraph-cli.""" + """Top-level config for langgraph-cli or similar deployment tooling.""" python_version: str - """Python version to use.""" + """Optional. Python version in 'major.minor' format (e.g. '3.11'). + Must be at least 3.11 or greater for this deployment to function properly. + """ node_version: Optional[str] - """Node.js version to use.""" + """Optional. Node.js version as a major version (e.g. '20'), if your deployment needs Node. + Must be >= 20 if provided. + """ pip_config_file: Optional[str] - """Path to a pip configuration file.""" + """Optional. Path to a pip config file (e.g., "/etc/pip.conf" or "pip.ini") for controlling + package installation (custom indices, credentials, etc.). + + Only relevant if Python dependencies are installed via pip. If omitted, default pip settings are used. + """ dockerfile_lines: list[str] - """Additional lines to add to the Dockerfile.""" + """Optional. Additional Docker instructions that will be appended to your base Dockerfile. + + Useful for installing OS packages, setting environment variables, etc. + Example: + dockerfile_lines=[ + "RUN apt-get update && apt-get install -y libmagic-dev", + "ENV MY_CUSTOM_VAR=hello_world" + ] + """ dependencies: list[str] - """Additional Python dependencies to install.""" + """List of Python dependencies to install, either from PyPI or local paths. + + Examples: + - "." or "./src" if you have a local Python package + - str (aka "anthropic") for a PyPI package + - "git+https://github.com/org/repo.git@main" for a Git-based package + Defaults to an empty list, meaning no additional packages installed beyond your base environment. + """ graphs: dict[str, str] - """Mapping of graph names to their definitions.""" + """Optional. Named definitions of graphs, each pointing to a Python object. + + + Graphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context + managers that accept a single configuration argument (of type RunnableConfig) and return a pregel object + (instance of Stategraph, etc.). + + Keys are graph names, values are "path/to/file.py:object_name". + Example: + { + "mygraph": "graphs/my_graph.py:graph_definition", + "anothergraph": "graphs/another.py:get_graph" + } + """ env: Union[dict[str, str], str] - """Environment variables to set. - - If a dictionary is provided, the keys are environment variable names - and the values are the corresponding environment variable values. - - If a string is provided, it is interpreted as a path to a file containing - environment variables in the format KEY=VALUE, with one environment variable - per line. + """Optional. Environment variables to set for your deployment. + + - If given as a dict, keys are variable names and values are their values. + - If given as a string, it must be a path to a file containing lines in KEY=VALUE format. + + Example as a dict: + env={"API_TOKEN": "abc123", "DEBUG": "true"} + Example as a file path: + env=".env" """ store: Optional[StoreConfig] - """Configuration for vector embeddings in store.""" + """Optional. Configuration for the built-in long-term memory store, including semantic search indexing. + + If omitted, no vector index is set up (the object store will still be present, however). + """ auth: Optional[AuthConfig] - """Configuration for authentication.""" + """Optional. Custom authentication config, including the path to your Python auth logic and + the OpenAPI security definitions it uses. + """ http: Optional[HttpConfig] - """Configuration for HTTP server.""" + """Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed + and how cross-origin requests are handled. + """ def _parse_version(version_str: str) -> tuple[int, int]: @@ -687,9 +867,11 @@ def python_config_to_docker( pip_pkgs_str = f"RUN {pip_install} {' '.join(pypi_deps)}" if pypi_deps else "" if local_deps.pip_reqs: pip_reqs_str = os.linesep.join( - f"COPY --from=__outer_{reqpath.name} requirements.txt {destpath}" - if reqpath.parent in local_deps.additional_contexts - else f"ADD {reqpath.relative_to(config_path.parent)} {destpath}" + ( + f"COPY --from=__outer_{reqpath.name} requirements.txt {destpath}" + if reqpath.parent in local_deps.additional_contexts + else f"ADD {reqpath.relative_to(config_path.parent)} {destpath}" + ) for reqpath, destpath in local_deps.pip_reqs ) pip_reqs_str += f'{os.linesep}RUN {pip_install} {" ".join("-r " + r for _,r in local_deps.pip_reqs)}' @@ -724,13 +906,15 @@ RUN set -ex && \\ ) local_pkgs_str = os.linesep.join( - f"""# -- Adding local package {relpath} -- + ( + f"""# -- Adding local package {relpath} -- COPY --from={name} . /deps/{name} # -- End of local package {relpath} --""" - if fullpath in local_deps.additional_contexts - else f"""# -- Adding local package {relpath} -- + if fullpath in local_deps.additional_contexts + else f"""# -- Adding local package {relpath} -- ADD {relpath} /deps/{name} # -- End of local package {relpath} --""" + ) for fullpath, (relpath, name) in local_deps.real_pkgs.items() ) diff --git a/libs/cli/poetry.lock b/libs/cli/poetry.lock index f3bdb61c4..e710fb217 100644 --- a/libs/cli/poetry.lock +++ b/libs/cli/poetry.lock @@ -707,6 +707,58 @@ files = [ {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, ] +[[package]] +name = "msgspec" +version = "0.19.0" +description = "A fast serialization and validation library, with builtin support for JSON, MessagePack, YAML, and TOML." +optional = false +python-versions = ">=3.9" +files = [ + {file = "msgspec-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d8dd848ee7ca7c8153462557655570156c2be94e79acec3561cf379581343259"}, + {file = "msgspec-0.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0553bbc77662e5708fe66aa75e7bd3e4b0f209709c48b299afd791d711a93c36"}, + {file = "msgspec-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe2c4bf29bf4e89790b3117470dea2c20b59932772483082c468b990d45fb947"}, + {file = "msgspec-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e87ecfa9795ee5214861eab8326b0e75475c2e68a384002aa135ea2a27d909"}, + {file = "msgspec-0.19.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3c4ec642689da44618f68c90855a10edbc6ac3ff7c1d94395446c65a776e712a"}, + {file = "msgspec-0.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2719647625320b60e2d8af06b35f5b12d4f4d281db30a15a1df22adb2295f633"}, + {file = "msgspec-0.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:695b832d0091edd86eeb535cd39e45f3919f48d997685f7ac31acb15e0a2ed90"}, + {file = "msgspec-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa77046904db764b0462036bc63ef71f02b75b8f72e9c9dd4c447d6da1ed8f8e"}, + {file = "msgspec-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:047cfa8675eb3bad68722cfe95c60e7afabf84d1bd8938979dd2b92e9e4a9551"}, + {file = "msgspec-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e78f46ff39a427e10b4a61614a2777ad69559cc8d603a7c05681f5a595ea98f7"}, + {file = "msgspec-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c7adf191e4bd3be0e9231c3b6dc20cf1199ada2af523885efc2ed218eafd011"}, + {file = "msgspec-0.19.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f04cad4385e20be7c7176bb8ae3dca54a08e9756cfc97bcdb4f18560c3042063"}, + {file = "msgspec-0.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45c8fb410670b3b7eb884d44a75589377c341ec1392b778311acdbfa55187716"}, + {file = "msgspec-0.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:70eaef4934b87193a27d802534dc466778ad8d536e296ae2f9334e182ac27b6c"}, + {file = "msgspec-0.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f98bd8962ad549c27d63845b50af3f53ec468b6318400c9f1adfe8b092d7b62f"}, + {file = "msgspec-0.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:43bbb237feab761b815ed9df43b266114203f53596f9b6e6f00ebd79d178cdf2"}, + {file = "msgspec-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cfc033c02c3e0aec52b71710d7f84cb3ca5eb407ab2ad23d75631153fdb1f12"}, + {file = "msgspec-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d911c442571605e17658ca2b416fd8579c5050ac9adc5e00c2cb3126c97f73bc"}, + {file = "msgspec-0.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:757b501fa57e24896cf40a831442b19a864f56d253679f34f260dcb002524a6c"}, + {file = "msgspec-0.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5f0f65f29b45e2816d8bded36e6b837a4bf5fb60ec4bc3c625fa2c6da4124537"}, + {file = "msgspec-0.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:067f0de1c33cfa0b6a8206562efdf6be5985b988b53dd244a8e06f993f27c8c0"}, + {file = "msgspec-0.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f12d30dd6266557aaaf0aa0f9580a9a8fbeadfa83699c487713e355ec5f0bd86"}, + {file = "msgspec-0.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82b2c42c1b9ebc89e822e7e13bbe9d17ede0c23c187469fdd9505afd5a481314"}, + {file = "msgspec-0.19.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19746b50be214a54239aab822964f2ac81e38b0055cca94808359d779338c10e"}, + {file = "msgspec-0.19.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60ef4bdb0ec8e4ad62e5a1f95230c08efb1f64f32e6e8dd2ced685bcc73858b5"}, + {file = "msgspec-0.19.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac7f7c377c122b649f7545810c6cd1b47586e3aa3059126ce3516ac7ccc6a6a9"}, + {file = "msgspec-0.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5bc1472223a643f5ffb5bf46ccdede7f9795078194f14edd69e3aab7020d327"}, + {file = "msgspec-0.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:317050bc0f7739cb30d257ff09152ca309bf5a369854bbf1e57dffc310c1f20f"}, + {file = "msgspec-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15c1e86fff77184c20a2932cd9742bf33fe23125fa3fcf332df9ad2f7d483044"}, + {file = "msgspec-0.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3b5541b2b3294e5ffabe31a09d604e23a88533ace36ac288fa32a420aa38d229"}, + {file = "msgspec-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f5c043ace7962ef188746e83b99faaa9e3e699ab857ca3f367b309c8e2c6b12"}, + {file = "msgspec-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca06aa08e39bf57e39a258e1996474f84d0dd8130d486c00bec26d797b8c5446"}, + {file = "msgspec-0.19.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e695dad6897896e9384cf5e2687d9ae9feaef50e802f93602d35458e20d1fb19"}, + {file = "msgspec-0.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3be5c02e1fee57b54130316a08fe40cca53af92999a302a6054cd451700ea7db"}, + {file = "msgspec-0.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:0684573a821be3c749912acf5848cce78af4298345cb2d7a8b8948a0a5a27cfe"}, + {file = "msgspec-0.19.0.tar.gz", hash = "sha256:604037e7cd475345848116e89c553aa9a233259733ab51986ac924ab1b976f8e"}, +] + +[package.extras] +dev = ["attrs", "coverage", "eval-type-backport", "furo", "ipython", "msgpack", "mypy", "pre-commit", "pyright", "pytest", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "tomli", "tomli_w"] +doc = ["furo", "ipython", "sphinx", "sphinx-copybutton", "sphinx-design"] +test = ["attrs", "eval-type-backport", "msgpack", "pytest", "pyyaml", "tomli", "tomli_w"] +toml = ["tomli", "tomli_w"] +yaml = ["pyyaml"] + [[package]] name = "mypy" version = "1.15.0" @@ -1665,4 +1717,4 @@ inmem = ["langgraph-api", "python-dotenv"] [metadata] lock-version = "2.0" python-versions = "^3.9.0,<4.0" -content-hash = "04a0b0e203ae00f30cca7e454c632be0b41cbb4820d0c05315a346d514b5f98e" +content-hash = "d0e2bdcb600ad031867413025fcc58bb162609209359d63ca99a77060cf8cbb4" diff --git a/libs/cli/pyproject.toml b/libs/cli/pyproject.toml index 0c9910cb9..8fb5bf4aa 100644 --- a/libs/cli/pyproject.toml +++ b/libs/cli/pyproject.toml @@ -25,6 +25,7 @@ pytest-asyncio = "^0.21.1" pytest-mock = "^3.11.1" pytest-watch = "^4.2.0" mypy = "^1.10.0" +msgspec = "^0.19.0" [tool.poetry.extras] inmem = ["langgraph-api", "python-dotenv"] diff --git a/libs/cli/schemas/schema.json b/libs/cli/schemas/schema.json new file mode 100644 index 000000000..8b674be52 --- /dev/null +++ b/libs/cli/schemas/schema.json @@ -0,0 +1,410 @@ +{ + "$ref": "#/$defs/Config", + "$defs": { + "Config": { + "title": "Config", + "description": "Top-level config for langgraph-cli or similar deployment tooling.", + "type": "object", + "required": [], + "oneOf": [ + { + "type": "object", + "properties": { + "python_version": { + "type": "string", + "description": "Optional. Python version in 'major.minor' format (e.g. '3.11').\nMust be at least 3.11 or greater for this deployment to function properly.\n", + "enum": [ + "3.11", + "3.12" + ] + }, + "pip_config_file": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, credentials, etc.).\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n" + }, + "auth": { + "anyOf": [ + { + "$ref": "#/$defs/AuthConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of Python dependencies to install, either from PyPI or local paths.\n" + }, + "dockerfile_lines": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. Additional Docker instructions that will be appended to your base Dockerfile.\n\nUseful for installing OS packages, setting environment variables, etc." + }, + "env": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "string" + } + ], + "description": "Optional. Environment variables to set for your deployment.\n\n- If given as a dict, keys are variable names and values are their values.\n- If given as a string, it must be a path to a file containing lines in KEY=VALUE format.\n\nenv=\".env\n" + }, + "graphs": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Optional. Named definitions of graphs, each pointing to a Python object.\n\n\nGraphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context\nmanagers that accept a single configuration argument (of type RunnableConfig) and return a pregel object\n(instance of Stategraph, etc.).\n" + }, + "http": { + "anyOf": [ + { + "$ref": "#/$defs/HttpConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed\nand how cross-origin requests are handled.\n" + }, + "store": { + "anyOf": [ + { + "$ref": "#/$defs/StoreConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in long-term memory store, including semantic search indexing.\n\nIf omitted, no vector index is set up (the object store will still be present, however).\n" + } + }, + "required": [ + "dependencies", + "graphs" + ] + }, + { + "type": "object", + "properties": { + "node_version": { + "anyOf": [ + { + "type": "string", + "enum": [ + "20" + ] + }, + { + "type": "null" + } + ], + "description": "Optional. Node.js version as a major version (e.g. '20'), if your deployment needs Node.\nMust be >= 20 if provided.\n" + }, + "auth": { + "anyOf": [ + { + "$ref": "#/$defs/AuthConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of Python dependencies to install, either from PyPI or local paths.\n" + }, + "dockerfile_lines": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. Additional Docker instructions that will be appended to your base Dockerfile.\n\nUseful for installing OS packages, setting environment variables, etc." + }, + "env": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "string" + } + ], + "description": "Optional. Environment variables to set for your deployment.\n\n- If given as a dict, keys are variable names and values are their values.\n- If given as a string, it must be a path to a file containing lines in KEY=VALUE format.\n\nenv=\".env\n" + }, + "graphs": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Optional. Named definitions of graphs, each pointing to a Python object.\n\n\nGraphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context\nmanagers that accept a single configuration argument (of type RunnableConfig) and return a pregel object\n(instance of Stategraph, etc.).\n" + }, + "http": { + "anyOf": [ + { + "$ref": "#/$defs/HttpConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed\nand how cross-origin requests are handled.\n" + }, + "store": { + "anyOf": [ + { + "$ref": "#/$defs/StoreConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in long-term memory store, including semantic search indexing.\n\nIf omitted, no vector index is set up (the object store will still be present, however).\n" + } + }, + "required": [ + "node_version", + "graphs" + ] + } + ] + }, + "AuthConfig": { + "title": "AuthConfig", + "description": "Configuration for custom authentication logic and how it integrates into the OpenAPI spec.", + "type": "object", + "properties": { + "disable_studio_auth": { + "type": "boolean", + "description": "Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio.\n\nDefaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header\nvalue is a valid API key for the deployment's workspace. If True, all requests will go through your custom\nauthentication logic, regardless of origin of the request.\n" + }, + "openapi": { + "$ref": "#/$defs/SecurityConfig", + "description": "Required. Detailed security configuration that merges into your deployment's OpenAPI spec.\n\n{\n}\n}\n}\n},\n]\n}\n" + }, + "path": { + "type": "string", + "description": "Required. Path to an instance of the Auth() class that implements custom authentication.\n" + } + }, + "required": [] + }, + "SecurityConfig": { + "title": "SecurityConfig", + "description": "Configuration for OpenAPI security definitions and requirements.\n\nUseful for specifying global or path-level authentication and authorization flows\n(e.g., OAuth2, API key headers, etc.).", + "type": "object", + "properties": { + "paths": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "description": "Optional. Path-specific security overrides.\n\n- Keys that are HTTP methods (e.g., \"GET\", \"POST\"),\n- Values are lists of security definitions (just like `security`) for that method.\n" + }, + "security": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "description": "Optional. Global security requirements across all endpoints.\n\nEach element in the list maps a security scheme (e.g. \"OAuth2\") to a list of scopes (e.g. [\"read\", \"write\"])." + }, + "securitySchemes": { + "type": "object", + "additionalProperties": { + "type": "object" + }, + "description": "Required. Dict describing each security scheme recognized by your OpenAPI spec.\n\nKeys are scheme names (e.g. \"OAuth2\", \"ApiKeyAuth\") and values are their definitions." + } + }, + "required": [] + }, + "HttpConfig": { + "title": "HttpConfig", + "description": "Configuration for the built-in HTTP server that powers your deployment's routes and endpoints.", + "type": "object", + "properties": { + "app": { + "type": "string", + "description": "Optional. Import path to a custom Starlette/FastAPI application to mount.\n" + }, + "cors": { + "anyOf": [ + { + "$ref": "#/$defs/CorsConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines CORS restrictions. If omitted, no special rules are set and\ncross-origin behavior depends on default server settings.\n" + }, + "disable_assistants": { + "type": "boolean", + "description": "Optional. If True, /assistants routes are removed from the server.\n\nDefault is False (meaning /assistants is enabled).\n" + }, + "disable_meta": { + "type": "boolean", + "description": "Optional. If True, all meta endpoints (/ok, /info, /metrics, /docs) are disabled.\n\nDefault is False.\n" + }, + "disable_runs": { + "type": "boolean", + "description": "Optional. If True, /runs routes are removed.\n\nDefault is False.\n" + }, + "disable_store": { + "type": "boolean", + "description": "Optional. If True, /store routes are removed, disabling direct store interactions via HTTP.\n\nDefault is False.\n" + }, + "disable_threads": { + "type": "boolean", + "description": "Optional. If True, /threads routes are removed.\n\nDefault is False.\n" + } + }, + "required": [] + }, + "CorsConfig": { + "title": "CorsConfig", + "description": "Specifies Cross-Origin Resource Sharing (CORS) rules for your server.\n\nIf omitted, defaults are typically very restrictive (often no cross-origin requests).\nConfigure carefully if you want to allow usage from browsers hosted on other domains.", + "type": "object", + "properties": { + "allow_credentials": { + "type": "boolean", + "description": "Optional. If True, cross-origin requests can include credentials (cookies, auth headers).\n\nDefault False to avoid accidentally exposing secured endpoints to untrusted sites.\n" + }, + "allow_headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. HTTP headers that can be used in cross-origin requests (e.g. [\"Content-Type\", \"Authorization\"])." + }, + "allow_methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. HTTP methods permitted for cross-origin requests (e.g. [\"GET\", \"POST\"]).\n\nDefault might be [\"GET\", \"POST\", \"OPTIONS\"] depending on your server framework.\n" + }, + "allow_origin_regex": { + "type": "string", + "description": "Optional. A regex pattern for matching allowed origins, used if you have dynamic subdomains.\n" + }, + "allow_origins": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. List of allowed origins (e.g., \"https://example.com\").\n\nDefault is often an empty list (no external origins).\nUse \"*\" only if you trust all origins, as that bypasses most restrictions.\n" + }, + "expose_headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. List of headers that browsers are allowed to read from the response in cross-origin contexts." + }, + "max_age": { + "type": "integer", + "description": "Optional. How many seconds the browser may cache preflight responses.\n\nDefault might be 600 (10 minutes). Larger values reduce preflight requests but can cause stale configurations.\n" + } + }, + "required": [] + }, + "StoreConfig": { + "title": "StoreConfig", + "description": "Configuration for the built-in long-term memory store.\n\nThis store can optionally perform semantic search. If you omit `index`,\nthe store will just handle traditional (non-embedded) data without vector lookups.", + "type": "object", + "properties": { + "index": { + "anyOf": [ + { + "$ref": "#/$defs/IndexConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines the vector-based semantic search configuration.\n\n- Generate embeddings according to `index.embed`\n- Enforce the embedding dimension given by `index.dims`\n- Embed only specified JSON fields (if any) from `index.fields`\n\nIf omitted, no vector index is initialized.\n" + } + }, + "required": [] + }, + "IndexConfig": { + "title": "IndexConfig", + "description": "Configuration for indexing documents for semantic search in the store.\n\nThis governs how text is converted into embeddings and stored for vector-based lookups.", + "type": "object", + "properties": { + "dims": { + "type": "integer", + "description": "Required. Dimensionality of the embedding vectors you will store.\n\nMust match the output dimension of your selected embedding model or custom embed function.\nIf mismatched, you will likely encounter shape/size errors when inserting or querying vectors.\n\n" + }, + "embed": { + "type": "string", + "description": "Required. Identifier or reference to the embedding model or a custom embedding function.\n\n- \"my_custom_embed\" if it's a known alias in your system\n" + }, + "fields": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Optional. List of JSON fields to extract before generating embeddings.\n\nDefaults to [\"$\"], which means the entire JSON object is embedded as one piece of text.\nIf you provide multiple fields (e.g. [\"title\", \"content\"]), each is extracted and embedded separately,\noften saving token usage if you only care about certain parts of the data.\n" + } + }, + "required": [] + } + }, + "title": "LangGraph CLI Configuration", + "description": "Configuration schema for langgraph-cli", + "version": "v0" +} \ No newline at end of file diff --git a/libs/cli/schemas/schema.v0.json b/libs/cli/schemas/schema.v0.json new file mode 100644 index 000000000..8b674be52 --- /dev/null +++ b/libs/cli/schemas/schema.v0.json @@ -0,0 +1,410 @@ +{ + "$ref": "#/$defs/Config", + "$defs": { + "Config": { + "title": "Config", + "description": "Top-level config for langgraph-cli or similar deployment tooling.", + "type": "object", + "required": [], + "oneOf": [ + { + "type": "object", + "properties": { + "python_version": { + "type": "string", + "description": "Optional. Python version in 'major.minor' format (e.g. '3.11').\nMust be at least 3.11 or greater for this deployment to function properly.\n", + "enum": [ + "3.11", + "3.12" + ] + }, + "pip_config_file": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, credentials, etc.).\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n" + }, + "auth": { + "anyOf": [ + { + "$ref": "#/$defs/AuthConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of Python dependencies to install, either from PyPI or local paths.\n" + }, + "dockerfile_lines": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. Additional Docker instructions that will be appended to your base Dockerfile.\n\nUseful for installing OS packages, setting environment variables, etc." + }, + "env": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "string" + } + ], + "description": "Optional. Environment variables to set for your deployment.\n\n- If given as a dict, keys are variable names and values are their values.\n- If given as a string, it must be a path to a file containing lines in KEY=VALUE format.\n\nenv=\".env\n" + }, + "graphs": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Optional. Named definitions of graphs, each pointing to a Python object.\n\n\nGraphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context\nmanagers that accept a single configuration argument (of type RunnableConfig) and return a pregel object\n(instance of Stategraph, etc.).\n" + }, + "http": { + "anyOf": [ + { + "$ref": "#/$defs/HttpConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed\nand how cross-origin requests are handled.\n" + }, + "store": { + "anyOf": [ + { + "$ref": "#/$defs/StoreConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in long-term memory store, including semantic search indexing.\n\nIf omitted, no vector index is set up (the object store will still be present, however).\n" + } + }, + "required": [ + "dependencies", + "graphs" + ] + }, + { + "type": "object", + "properties": { + "node_version": { + "anyOf": [ + { + "type": "string", + "enum": [ + "20" + ] + }, + { + "type": "null" + } + ], + "description": "Optional. Node.js version as a major version (e.g. '20'), if your deployment needs Node.\nMust be >= 20 if provided.\n" + }, + "auth": { + "anyOf": [ + { + "$ref": "#/$defs/AuthConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of Python dependencies to install, either from PyPI or local paths.\n" + }, + "dockerfile_lines": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. Additional Docker instructions that will be appended to your base Dockerfile.\n\nUseful for installing OS packages, setting environment variables, etc." + }, + "env": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "string" + } + ], + "description": "Optional. Environment variables to set for your deployment.\n\n- If given as a dict, keys are variable names and values are their values.\n- If given as a string, it must be a path to a file containing lines in KEY=VALUE format.\n\nenv=\".env\n" + }, + "graphs": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Optional. Named definitions of graphs, each pointing to a Python object.\n\n\nGraphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context\nmanagers that accept a single configuration argument (of type RunnableConfig) and return a pregel object\n(instance of Stategraph, etc.).\n" + }, + "http": { + "anyOf": [ + { + "$ref": "#/$defs/HttpConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed\nand how cross-origin requests are handled.\n" + }, + "store": { + "anyOf": [ + { + "$ref": "#/$defs/StoreConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in long-term memory store, including semantic search indexing.\n\nIf omitted, no vector index is set up (the object store will still be present, however).\n" + } + }, + "required": [ + "node_version", + "graphs" + ] + } + ] + }, + "AuthConfig": { + "title": "AuthConfig", + "description": "Configuration for custom authentication logic and how it integrates into the OpenAPI spec.", + "type": "object", + "properties": { + "disable_studio_auth": { + "type": "boolean", + "description": "Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio.\n\nDefaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header\nvalue is a valid API key for the deployment's workspace. If True, all requests will go through your custom\nauthentication logic, regardless of origin of the request.\n" + }, + "openapi": { + "$ref": "#/$defs/SecurityConfig", + "description": "Required. Detailed security configuration that merges into your deployment's OpenAPI spec.\n\n{\n}\n}\n}\n},\n]\n}\n" + }, + "path": { + "type": "string", + "description": "Required. Path to an instance of the Auth() class that implements custom authentication.\n" + } + }, + "required": [] + }, + "SecurityConfig": { + "title": "SecurityConfig", + "description": "Configuration for OpenAPI security definitions and requirements.\n\nUseful for specifying global or path-level authentication and authorization flows\n(e.g., OAuth2, API key headers, etc.).", + "type": "object", + "properties": { + "paths": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "description": "Optional. Path-specific security overrides.\n\n- Keys that are HTTP methods (e.g., \"GET\", \"POST\"),\n- Values are lists of security definitions (just like `security`) for that method.\n" + }, + "security": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "description": "Optional. Global security requirements across all endpoints.\n\nEach element in the list maps a security scheme (e.g. \"OAuth2\") to a list of scopes (e.g. [\"read\", \"write\"])." + }, + "securitySchemes": { + "type": "object", + "additionalProperties": { + "type": "object" + }, + "description": "Required. Dict describing each security scheme recognized by your OpenAPI spec.\n\nKeys are scheme names (e.g. \"OAuth2\", \"ApiKeyAuth\") and values are their definitions." + } + }, + "required": [] + }, + "HttpConfig": { + "title": "HttpConfig", + "description": "Configuration for the built-in HTTP server that powers your deployment's routes and endpoints.", + "type": "object", + "properties": { + "app": { + "type": "string", + "description": "Optional. Import path to a custom Starlette/FastAPI application to mount.\n" + }, + "cors": { + "anyOf": [ + { + "$ref": "#/$defs/CorsConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines CORS restrictions. If omitted, no special rules are set and\ncross-origin behavior depends on default server settings.\n" + }, + "disable_assistants": { + "type": "boolean", + "description": "Optional. If True, /assistants routes are removed from the server.\n\nDefault is False (meaning /assistants is enabled).\n" + }, + "disable_meta": { + "type": "boolean", + "description": "Optional. If True, all meta endpoints (/ok, /info, /metrics, /docs) are disabled.\n\nDefault is False.\n" + }, + "disable_runs": { + "type": "boolean", + "description": "Optional. If True, /runs routes are removed.\n\nDefault is False.\n" + }, + "disable_store": { + "type": "boolean", + "description": "Optional. If True, /store routes are removed, disabling direct store interactions via HTTP.\n\nDefault is False.\n" + }, + "disable_threads": { + "type": "boolean", + "description": "Optional. If True, /threads routes are removed.\n\nDefault is False.\n" + } + }, + "required": [] + }, + "CorsConfig": { + "title": "CorsConfig", + "description": "Specifies Cross-Origin Resource Sharing (CORS) rules for your server.\n\nIf omitted, defaults are typically very restrictive (often no cross-origin requests).\nConfigure carefully if you want to allow usage from browsers hosted on other domains.", + "type": "object", + "properties": { + "allow_credentials": { + "type": "boolean", + "description": "Optional. If True, cross-origin requests can include credentials (cookies, auth headers).\n\nDefault False to avoid accidentally exposing secured endpoints to untrusted sites.\n" + }, + "allow_headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. HTTP headers that can be used in cross-origin requests (e.g. [\"Content-Type\", \"Authorization\"])." + }, + "allow_methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. HTTP methods permitted for cross-origin requests (e.g. [\"GET\", \"POST\"]).\n\nDefault might be [\"GET\", \"POST\", \"OPTIONS\"] depending on your server framework.\n" + }, + "allow_origin_regex": { + "type": "string", + "description": "Optional. A regex pattern for matching allowed origins, used if you have dynamic subdomains.\n" + }, + "allow_origins": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. List of allowed origins (e.g., \"https://example.com\").\n\nDefault is often an empty list (no external origins).\nUse \"*\" only if you trust all origins, as that bypasses most restrictions.\n" + }, + "expose_headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. List of headers that browsers are allowed to read from the response in cross-origin contexts." + }, + "max_age": { + "type": "integer", + "description": "Optional. How many seconds the browser may cache preflight responses.\n\nDefault might be 600 (10 minutes). Larger values reduce preflight requests but can cause stale configurations.\n" + } + }, + "required": [] + }, + "StoreConfig": { + "title": "StoreConfig", + "description": "Configuration for the built-in long-term memory store.\n\nThis store can optionally perform semantic search. If you omit `index`,\nthe store will just handle traditional (non-embedded) data without vector lookups.", + "type": "object", + "properties": { + "index": { + "anyOf": [ + { + "$ref": "#/$defs/IndexConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines the vector-based semantic search configuration.\n\n- Generate embeddings according to `index.embed`\n- Enforce the embedding dimension given by `index.dims`\n- Embed only specified JSON fields (if any) from `index.fields`\n\nIf omitted, no vector index is initialized.\n" + } + }, + "required": [] + }, + "IndexConfig": { + "title": "IndexConfig", + "description": "Configuration for indexing documents for semantic search in the store.\n\nThis governs how text is converted into embeddings and stored for vector-based lookups.", + "type": "object", + "properties": { + "dims": { + "type": "integer", + "description": "Required. Dimensionality of the embedding vectors you will store.\n\nMust match the output dimension of your selected embedding model or custom embed function.\nIf mismatched, you will likely encounter shape/size errors when inserting or querying vectors.\n\n" + }, + "embed": { + "type": "string", + "description": "Required. Identifier or reference to the embedding model or a custom embedding function.\n\n- \"my_custom_embed\" if it's a known alias in your system\n" + }, + "fields": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Optional. List of JSON fields to extract before generating embeddings.\n\nDefaults to [\"$\"], which means the entire JSON object is embedded as one piece of text.\nIf you provide multiple fields (e.g. [\"title\", \"content\"]), each is extracted and embedded separately,\noften saving token usage if you only care about certain parts of the data.\n" + } + }, + "required": [] + } + }, + "title": "LangGraph CLI Configuration", + "description": "Configuration schema for langgraph-cli", + "version": "v0" +} \ No newline at end of file