From 59d0b154a06cb068b171b1beaca8c4cb8ea02527 Mon Sep 17 00:00:00 2001 From: infra Date: Wed, 13 Dec 2023 18:01:26 -0800 Subject: [PATCH 1/4] Remove unused docker files and add version --- js/src/cli/docker-compose.beta.yaml | 19 -- js/src/cli/docker-compose.dev.yaml | 19 -- js/src/cli/docker-compose.ngrok.yaml | 17 -- js/src/cli/docker-compose.yaml | 10 +- js/src/cli/main.ts | 163 ++------------- python/langsmith/cli/docker-compose.beta.yaml | 19 -- python/langsmith/cli/docker-compose.dev.yaml | 19 -- .../langsmith/cli/docker-compose.ngrok.yaml | 17 -- python/langsmith/cli/docker-compose.yaml | 10 +- python/langsmith/cli/main.py | 197 +++--------------- python/tests/unit_tests/cli/test_main.py | 21 -- 11 files changed, 62 insertions(+), 449 deletions(-) delete mode 100644 js/src/cli/docker-compose.beta.yaml delete mode 100644 js/src/cli/docker-compose.dev.yaml delete mode 100644 js/src/cli/docker-compose.ngrok.yaml delete mode 100644 python/langsmith/cli/docker-compose.beta.yaml delete mode 100644 python/langsmith/cli/docker-compose.dev.yaml delete mode 100644 python/langsmith/cli/docker-compose.ngrok.yaml diff --git a/js/src/cli/docker-compose.beta.yaml b/js/src/cli/docker-compose.beta.yaml deleted file mode 100644 index 8d5ecc31f..000000000 --- a/js/src/cli/docker-compose.beta.yaml +++ /dev/null @@ -1,19 +0,0 @@ -version: '3' -services: - # TODO: Move to the regular docker-compose.yaml once deployed - langchain-hub: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:latest - environment: - - PORT=1985 - - LANGCHAIN_ENV=local_docker - - LOG_LEVEL=warning - - LANGSMITH_LICENSE_KEY=${LANGSMITH_LICENSE_KEY} - ports: - - 1985:1985 - depends_on: - - langchain-db - langchain-db: - volumes: - - rc-langchain-db-data:/var/lib/postgresql/data -volumes: - rc-langchain-db-data: diff --git a/js/src/cli/docker-compose.dev.yaml b/js/src/cli/docker-compose.dev.yaml deleted file mode 100644 index 6e480093f..000000000 --- a/js/src/cli/docker-compose.dev.yaml +++ /dev/null @@ -1,19 +0,0 @@ -version: '3' -services: - # TODO: Move to the regular docker-compose.yaml once deployed - langchain-hub: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:latest - environment: - - PORT=1985 - - LANGCHAIN_ENV=local_docker - - LOG_LEVEL=warning - - LANGSMITH_LICENSE_KEY=${LANGSMITH_LICENSE_KEY} - ports: - - 1985:1985 - depends_on: - - langchain-db - langchain-db: - volumes: - - dev-langchain-db-data:/var/lib/postgresql/data -volumes: - dev-langchain-db-data: diff --git a/js/src/cli/docker-compose.ngrok.yaml b/js/src/cli/docker-compose.ngrok.yaml deleted file mode 100644 index e094ae5a4..000000000 --- a/js/src/cli/docker-compose.ngrok.yaml +++ /dev/null @@ -1,17 +0,0 @@ -version: '3' -services: - ngrok: - image: ngrok/ngrok:latest - restart: unless-stopped - command: - - "start" - - "--all" - - "--config" - - "/etc/ngrok.yml" - volumes: - - ./ngrok_config.yaml:/etc/ngrok.yml - ports: - - 4040:4040 - langchain-backend: - depends_on: - - ngrok diff --git a/js/src/cli/docker-compose.yaml b/js/src/cli/docker-compose.yaml index 5730298e1..345658102 100644 --- a/js/src/cli/docker-compose.yaml +++ b/js/src/cli/docker-compose.yaml @@ -1,11 +1,11 @@ version: "3" services: langchain-playground: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-playground:latest + image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-playground:${_LANGSMITH_IMAGE_VERSION-:latest} ports: - 3001:3001 langchain-frontend: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-frontend-dynamic:latest + image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-frontend-dynamic:${_LANGSMITH_IMAGE_VERSION-:latest} ports: - 80:80 volumes: @@ -15,7 +15,7 @@ services: - langchain-playground - langchain-hub langchain-backend: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:latest + image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:${_LANGSMITH_IMAGE_VERSION-:latest} environment: - PORT=1984 - LANGCHAIN_ENV=local_docker @@ -28,14 +28,14 @@ services: - langchain-db - langchain-redis langchain-queue: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:latest + image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:${_LANGSMITH_IMAGE_VERSION-:latest} environment: - LANGCHAIN_ENV=local_docker - LOG_LEVEL=warning - LANGSMITH_LICENSE_KEY=${LANGSMITH_LICENSE_KEY} entrypoint: "rq worker --with-scheduler -u redis://langchain-redis:6379 --serializer lc_database.queue.serializer.ORJSONSerializer --worker-class lc_database.queue.worker.Worker --connection-class lc_database.queue.connection.RedisRetry --job-class lc_database.queue.job.AsyncJob" langchain-hub: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:latest + image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:${_LANGSMITH_IMAGE_VERSION-:latest} environment: - PORT=1985 - LANGCHAIN_ENV=local_docker diff --git a/js/src/cli/main.ts b/js/src/cli/main.ts index 099d5c93b..68ebe1a31 100644 --- a/js/src/cli/main.ts +++ b/js/src/cli/main.ts @@ -1,5 +1,4 @@ import * as child_process from "child_process"; -import * as fs from "fs"; import * as path from "path"; import * as util from "util"; @@ -13,8 +12,6 @@ import { Command } from "commander"; import { spawn } from "child_process"; const currentFileName = __filename; -const currentDirName = __dirname; - const program = new Command(); async function getDockerComposeCommand(): Promise { @@ -69,71 +66,18 @@ async function pprintServices(servicesStatus: any[]) { serviceMessage.push(serviceStr + stateStr + portsStr); } - let langchainEndpoint = "http://localhost:1984"; - const usedNgrok = services.some((service) => - service["Service"].includes("ngrok") - ); - if (usedNgrok) { - langchainEndpoint = await getNgrokUrl(); - } - serviceMessage.push( "\nTo connect, set the following environment variables" + " in your LangChain application:" + "\nLANGCHAIN_TRACING_V2=true" + - `\nLANGCHAIN_ENDPOINT=${langchainEndpoint}` + `\nLANGCHAIN_ENDPOINT=http://localhost:80/api` ); console.info(serviceMessage.join("\n")); } -async function getNgrokUrl(): Promise { - const ngrokUrl = "http://localhost:4040/api/tunnels"; - try { - // const response = await axios.get(ngrokUrl); - const response = await fetch(ngrokUrl); - if (response.status !== 200) { - throw new Error( - `Could not connect to ngrok console. ${response.status}, ${response.statusText}` - ); - } - const result = await response.json(); - const exposedUrl = result["tunnels"][0]["public_url"]; - return exposedUrl; - } catch (error) { - throw new Error(`Could not connect to ngrok console. ${error}`); - } -} - -async function createNgrokConfig(authToken: string | null): Promise { - const configPath = path.join(currentDirName, "ngrok_config.yaml"); - // Check if is a directory - if (fs.existsSync(configPath) && fs.lstatSync(configPath).isDirectory()) { - fs.rmdirSync(configPath, { recursive: true }); - } else if (fs.existsSync(configPath)) { - fs.unlinkSync(configPath); - } - let ngrokConfig = ` -region: us -tunnels: - langchain: - addr: langchain-backend:1984 - proto: http -version: '2' -`; - - if (authToken !== null) { - ngrokConfig += `authtoken: ${authToken}`; - } - fs.writeFileSync(configPath, ngrokConfig); - return configPath; -} - class SmithCommand { dockerComposeCommand: string[] = []; dockerComposeFile = ""; - dockerComposeDevFile = ""; - dockerComposeBetaFile = ""; - ngrokPath = ""; constructor({ dockerComposeCommand }: { dockerComposeCommand: string[] }) { this.dockerComposeCommand = dockerComposeCommand; @@ -141,18 +85,6 @@ class SmithCommand { path.dirname(currentFileName), "docker-compose.yaml" ); - this.dockerComposeDevFile = path.join( - path.dirname(currentFileName), - "docker-compose.dev.yaml" - ); - this.dockerComposeBetaFile = path.join( - path.dirname(currentFileName), - "docker-compose.beta.yaml" - ); - this.ngrokPath = path.join( - path.dirname(currentFileName), - "docker-compose.ngrok.yaml" - ); } async executeCommand(command: string[]) { @@ -183,12 +115,14 @@ class SmithCommand { return new SmithCommand({ dockerComposeCommand }); } - async pull({ stage = "prod" }) { + async pull({ stage = "prod", version = "latest" }) { if (stage === "dev") { setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "dev-"); } else if (stage === "beta") { setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "rc-"); } + setEnvironmentVariable("_LANGSMITH_IMAGE_VERSION", version) + const command = [ ...this.dockerComposeCommand, @@ -199,19 +133,13 @@ class SmithCommand { await this.executeCommand(command); } - async startLocal(stage = "prod") { + async startLocal() { const command = [ ...this.dockerComposeCommand, "-f", this.dockerComposeFile, ]; - if (stage === "dev") { - command.push("-f", this.dockerComposeDevFile); - } else if (stage === "beta") { - command.push("-f", this.dockerComposeBetaFile); - } - command.push("up", "--quiet-pull", "--wait"); await this.executeCommand(command); @@ -224,42 +152,7 @@ class SmithCommand { ); console.info("\tLANGCHAIN_TRACING_V2=true"); - } - - async startAndExpose(ngrokAuthToken: string | null, stage = "prod") { - const configPath = await createNgrokConfig(ngrokAuthToken); - const command = [ - ...this.dockerComposeCommand, - "-f", - this.dockerComposeFile, - "-f", - this.ngrokPath, - ]; - - if (stage === "dev") { - command.push("-f", this.dockerComposeDevFile); - } else if (stage === "beta") { - command.push("-f", this.dockerComposeBetaFile); - } - - command.push("up", "--quiet-pull", "--wait"); - await this.executeCommand(command); - - console.info( - "ngrok is running. You can view the dashboard at http://0.0.0.0:4040" - ); - const ngrokUrl = await getNgrokUrl(); - console.info( - "LangSmith server is running at http://localhost:1984." + - "To view the app, navigate your browser to http://localhost:80" + - "\n\nTo connect your LangChain application to the server" + - " remotely, set the following environment variable" + - " when running your LangChain application." - ); - console.info("\tLANGCHAIN_TRACING_V2=true"); - console.info(`\tLANGCHAIN_ENDPOINT=${ngrokUrl}`); - - fs.unlinkSync(configPath); + console.info("\tLANGCHAIN_ENDPOINT=http://localhost:80/api"); } async stop() { @@ -267,8 +160,6 @@ class SmithCommand { ...this.dockerComposeCommand, "-f", this.dockerComposeFile, - "-f", - this.ngrokPath, "down", ]; await this.executeCommand(command); @@ -314,14 +205,6 @@ class SmithCommand { const startCommand = new Command("start") .description("Start the LangSmith server") - .option( - "--expose", - "Expose the server to the internet via ngrok (requires ngrok to be installed)" - ) - .option( - "--ngrok-authtoken ", - "Your ngrok auth token. If this is set, --expose is implied." - ) .option( "--stage ", "Which version of LangSmith to run. Options: prod, dev, beta (default: prod)" @@ -338,25 +221,23 @@ const startCommand = new Command("start") " License Key will be read from the LANGSMITH_LICENSE_KEY environment variable." + " If neither are provided, the Langsmith application will not spin up." ) + .option( + "--version ", +"The LangSmith version to use for LangSmith. Defaults to latest." + + " We recommend pegging this to the latest static version available at" + + " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" + + " if you are using Langsmith in production." + ) .action(async (args) => { const smith = await SmithCommand.create(); - if (args.stage === "dev") { - setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "dev-"); - } else if (args.stage === "beta") { - setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "rc-"); - } if (args.openaiApiKey) { setEnvironmentVariable("OPENAI_API_KEY", args.openaiApiKey); } if (args.langsmithLicenseKey) { setEnvironmentVariable("LANGSMITH_LICENSE_KEY", args.langsmithLicenseKey); } - await smith.pull({ stage: args.stage }); - if (args.expose) { - await smith.startAndExpose(args.ngrokAuthtoken, args.stage); - } else { - await smith.startLocal(args.stage); - } + await smith.pull({ stage: args.stage, version: args.version }); + await smith.startLocal(); }); const stopCommand = new Command("stop") @@ -372,14 +253,16 @@ const pullCommand = new Command("pull") "--stage ", "Which version of LangSmith to pull. Options: prod, dev, beta (default: prod)" ) + .option( + "--version ", +"The LangSmith version to use for LangSmith. Defaults to latest." + + " We recommend pegging this to the latest static version available at" + + " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" + + " if you are using Langsmith in production." + ) .action(async (args) => { const smith = await SmithCommand.create(); - if (args.stage === "dev") { - setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "dev-"); - } else if (args.stage === "beta") { - setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "rc-"); - } - await smith.pull({ stage: args.stage }); + await smith.pull({ stage: args.stage, version: args.version }); }); const statusCommand = new Command("status") diff --git a/python/langsmith/cli/docker-compose.beta.yaml b/python/langsmith/cli/docker-compose.beta.yaml deleted file mode 100644 index 8d5ecc31f..000000000 --- a/python/langsmith/cli/docker-compose.beta.yaml +++ /dev/null @@ -1,19 +0,0 @@ -version: '3' -services: - # TODO: Move to the regular docker-compose.yaml once deployed - langchain-hub: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:latest - environment: - - PORT=1985 - - LANGCHAIN_ENV=local_docker - - LOG_LEVEL=warning - - LANGSMITH_LICENSE_KEY=${LANGSMITH_LICENSE_KEY} - ports: - - 1985:1985 - depends_on: - - langchain-db - langchain-db: - volumes: - - rc-langchain-db-data:/var/lib/postgresql/data -volumes: - rc-langchain-db-data: diff --git a/python/langsmith/cli/docker-compose.dev.yaml b/python/langsmith/cli/docker-compose.dev.yaml deleted file mode 100644 index 6e480093f..000000000 --- a/python/langsmith/cli/docker-compose.dev.yaml +++ /dev/null @@ -1,19 +0,0 @@ -version: '3' -services: - # TODO: Move to the regular docker-compose.yaml once deployed - langchain-hub: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:latest - environment: - - PORT=1985 - - LANGCHAIN_ENV=local_docker - - LOG_LEVEL=warning - - LANGSMITH_LICENSE_KEY=${LANGSMITH_LICENSE_KEY} - ports: - - 1985:1985 - depends_on: - - langchain-db - langchain-db: - volumes: - - dev-langchain-db-data:/var/lib/postgresql/data -volumes: - dev-langchain-db-data: diff --git a/python/langsmith/cli/docker-compose.ngrok.yaml b/python/langsmith/cli/docker-compose.ngrok.yaml deleted file mode 100644 index e094ae5a4..000000000 --- a/python/langsmith/cli/docker-compose.ngrok.yaml +++ /dev/null @@ -1,17 +0,0 @@ -version: '3' -services: - ngrok: - image: ngrok/ngrok:latest - restart: unless-stopped - command: - - "start" - - "--all" - - "--config" - - "/etc/ngrok.yml" - volumes: - - ./ngrok_config.yaml:/etc/ngrok.yml - ports: - - 4040:4040 - langchain-backend: - depends_on: - - ngrok diff --git a/python/langsmith/cli/docker-compose.yaml b/python/langsmith/cli/docker-compose.yaml index 5730298e1..345658102 100644 --- a/python/langsmith/cli/docker-compose.yaml +++ b/python/langsmith/cli/docker-compose.yaml @@ -1,11 +1,11 @@ version: "3" services: langchain-playground: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-playground:latest + image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-playground:${_LANGSMITH_IMAGE_VERSION-:latest} ports: - 3001:3001 langchain-frontend: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-frontend-dynamic:latest + image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-frontend-dynamic:${_LANGSMITH_IMAGE_VERSION-:latest} ports: - 80:80 volumes: @@ -15,7 +15,7 @@ services: - langchain-playground - langchain-hub langchain-backend: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:latest + image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:${_LANGSMITH_IMAGE_VERSION-:latest} environment: - PORT=1984 - LANGCHAIN_ENV=local_docker @@ -28,14 +28,14 @@ services: - langchain-db - langchain-redis langchain-queue: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:latest + image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:${_LANGSMITH_IMAGE_VERSION-:latest} environment: - LANGCHAIN_ENV=local_docker - LOG_LEVEL=warning - LANGSMITH_LICENSE_KEY=${LANGSMITH_LICENSE_KEY} entrypoint: "rq worker --with-scheduler -u redis://langchain-redis:6379 --serializer lc_database.queue.serializer.ORJSONSerializer --worker-class lc_database.queue.worker.Worker --connection-class lc_database.queue.connection.RedisRetry --job-class lc_database.queue.job.AsyncJob" langchain-hub: - image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:latest + image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:${_LANGSMITH_IMAGE_VERSION-:latest} environment: - PORT=1985 - LANGCHAIN_ENV=local_docker diff --git a/python/langsmith/cli/main.py b/python/langsmith/cli/main.py index 1335e588d..a60a7c024 100644 --- a/python/langsmith/cli/main.py +++ b/python/langsmith/cli/main.py @@ -2,13 +2,9 @@ import json import logging import os -import shutil import subprocess -from contextlib import contextmanager from pathlib import Path -from typing import Dict, Generator, List, Literal, Mapping, Optional, Union, cast - -import requests +from typing import Dict, List, Literal, Mapping, Optional, Union, cast from langsmith import env as ls_env from langsmith import utils as ls_utils @@ -49,87 +45,15 @@ def pprint_services(services_status: List[Mapping[str, Union[str, List[str]]]]) ports_str = service.get("PublishedPorts", "") service_message.append(service_str + state_str + ports_str) - langchain_endpoint: str = "http://localhost:1984" - used_ngrok = any(["ngrok" in service["Service"] for service in services]) - if used_ngrok: - langchain_endpoint = get_ngrok_url(auth_token=None) - service_message.append( "\nTo connect, set the following environment variables" " in your LangChain application:" "\nLANGCHAIN_TRACING_V2=true" - f"\nLANGCHAIN_ENDPOINT={langchain_endpoint}" + "\nLANGCHAIN_ENDPOINT=http://localhost:80/api" ) logger.info("\n".join(service_message)) -def get_ngrok_url(auth_token: Optional[str]) -> str: - """Get the ngrok URL for the LangSmith server.""" - ngrok_url = "http://localhost:4040/api/tunnels" - try: - response = requests.get(ngrok_url) - response.raise_for_status() - exposed_url = response.json()["tunnels"][0]["public_url"] - except requests.exceptions.HTTPError: - raise ValueError("Could not connect to ngrok console.") - except (KeyError, IndexError): - message = "ngrok failed to start correctly. " - if auth_token is not None: - message += "Please check that your authtoken is correct." - raise ValueError(message) - return exposed_url - - -def _dumps_yaml(config: dict, depth: int = 0) -> str: - """Dump a dictionary to a YAML string without using any imports. - - We can assume it's all strings, ints, or dictionaries, up to 3 layers deep - """ - lines = [] - prefix = " " * depth - for key, value in config.items(): - if isinstance(value, dict): - lines.append(f"{prefix}{key}:") - lines.append(_dumps_yaml(value, depth + 1)) - else: - lines.append(f"{prefix}{key}: {value}") - return "\n".join(lines) - - -@contextmanager -def create_ngrok_config( - auth_token: Optional[str] = None, -) -> Generator[Path, None, None]: - """Create the ngrok configuration file.""" - config_path = _DIR / "ngrok_config.yaml" - if config_path.exists(): - # If there was an error in a prior run, it's possible - # Docker made this a directory instead of a file - if config_path.is_dir(): - shutil.rmtree(config_path) - else: - config_path.unlink() - ngrok_config = { - "tunnels": { - "langchain": { - "proto": "http", - "addr": "langchain-backend:1984", - } - }, - "version": "2", - "region": "us", - } - if auth_token is not None: - ngrok_config["authtoken"] = auth_token - config_path = _DIR / "ngrok_config.yaml" - with config_path.open("w") as f: - s = _dumps_yaml(ngrok_config) - f.write(s) - yield config_path - # Delete the config file after use - config_path.unlink(missing_ok=True) - - class LangSmithCommand: """Manage the LangSmith Tracing server.""" @@ -137,13 +61,6 @@ def __init__(self) -> None: self.docker_compose_file = ( Path(__file__).absolute().parent / "docker-compose.yaml" ) - self.docker_compose_dev_file = ( - Path(__file__).absolute().parent / "docker-compose.dev.yaml" - ) - self.docker_compose_beta_file = ( - Path(__file__).absolute().parent / "docker-compose.beta.yaml" - ) - self.ngrok_path = Path(__file__).absolute().parent / "docker-compose.ngrok.yaml" @property def docker_compose_command(self) -> List[str]: @@ -155,20 +72,12 @@ def _open_browser(self, url: str) -> None: except FileNotFoundError: pass - def _start_local( - self, stage: Union[Literal["prod"], Literal["dev"], Literal["beta"]] = "prod" - ) -> None: + def _start_local(self) -> None: command = [ *self.docker_compose_command, "-f", str(self.docker_compose_file), ] - if stage == "dev": - command.append("-f") - command.append(str(self.docker_compose_dev_file)) - elif stage == "beta": - command.append("-f") - command.append(str(self.docker_compose_beta_file)) subprocess.run( [ *command, @@ -178,7 +87,7 @@ def _start_local( ] ) logger.info( - "LangSmith server is running at http://localhost:1984.\n" + "LangSmith server is running at http://localhost:80/api.\n" "To view the app, navigate your browser to http://localhost:80" "\n\nTo connect your LangChain application to the server" " locally,\nset the following environment variable" @@ -186,55 +95,14 @@ def _start_local( ) logger.info("\tLANGCHAIN_TRACING_V2=true") - self._open_browser("http://localhost") - - def _start_and_expose( - self, - auth_token: Optional[str], - stage: Union[Literal["prod"], Literal["dev"], Literal["beta"]], - ) -> None: - with create_ngrok_config(auth_token=auth_token): - command = [ - *self.docker_compose_command, - "-f", - str(self.docker_compose_file), - "-f", - str(self.ngrok_path), - ] - if stage == "dev": - command.append("-f") - command.append(str(self.docker_compose_dev_file)) - elif stage == "beta": - command.append("-f") - command.append(str(self.docker_compose_beta_file)) - - subprocess.run( - [ - *command, - "up", - "--quiet-pull", - "--wait", - ] - ) - logger.info( - "ngrok is running. You can view the dashboard at http://0.0.0.0:4040" - ) - ngrok_url = get_ngrok_url(auth_token) - logger.info( - "LangSmith server is running at http://localhost:1984." - "\nTo view the app, navigate your browser to http://localhost:80" - " To connect remotely, set the following environment" - " variable when running your LangChain application." - ) - logger.info("\tLANGCHAIN_TRACING_V2=true") - logger.info(f"\tLANGCHAIN_ENDPOINT={ngrok_url}") - self._open_browser("http://0.0.0.0:4040") + logger.info("\tLANGCHAIN_ENDPOINT=http://localhost:80/api\n") self._open_browser("http://localhost") def pull( self, *, stage: Union[Literal["prod"], Literal["dev"], Literal["beta"]] = "prod", + version: str = "latest", ) -> None: """Pull the latest LangSmith images. @@ -246,6 +114,7 @@ def pull( os.environ["_LANGSMITH_IMAGE_PREFIX"] = "dev-" elif stage == "beta": os.environ["_LANGSMITH_IMAGE_PREFIX"] = "rc-" + os.environ["_LANGSMITH_IMAGE_VERSION"] = version subprocess.run( [ *self.docker_compose_command, @@ -258,11 +127,10 @@ def pull( def start( self, *, - expose: bool = False, - auth_token: Optional[str] = None, stage: Union[Literal["prod"], Literal["dev"], Literal["beta"]] = "prod", openai_api_key: Optional[str] = None, langsmith_license_key: str, + version: str = "latest", ) -> None: """Run the LangSmith server locally. @@ -281,19 +149,12 @@ def start( LANGSMITH_LICENSE_KEY environment variable. If neither are provided, Langsmith will not start up. """ - if stage == "dev": - os.environ["_LANGSMITH_IMAGE_PREFIX"] = "dev-" - elif stage == "beta": - os.environ["_LANGSMITH_IMAGE_PREFIX"] = "rc-" if openai_api_key is not None: os.environ["OPENAI_API_KEY"] = openai_api_key if langsmith_license_key is not None: os.environ["LANGSMITH_LICENSE_KEY"] = langsmith_license_key - self.pull(stage=stage) - if expose: - self._start_and_expose(auth_token=auth_token, stage=stage) - else: - self._start_local(stage=stage) + self.pull(stage=stage, version=version) + self._start_local() def stop(self, clear_volumes: bool = False) -> None: """Stop the LangSmith server.""" @@ -301,9 +162,7 @@ def stop(self, clear_volumes: bool = False) -> None: *self.docker_compose_command, "-f", str(self.docker_compose_file), - "-f", - str(self.ngrok_path), - "down", + "down" ] if clear_volumes: confirm = input( @@ -325,8 +184,6 @@ def logs(self) -> None: *self.docker_compose_command, "-f", str(self.docker_compose_file), - "-f", - str(self.ngrok_path), "logs", ] ) @@ -388,17 +245,6 @@ def main() -> None: server_start_parser = subparsers.add_parser( "start", description="Start the LangSmith server." ) - server_start_parser.add_argument( - "--expose", - action="store_true", - help="Expose the server to the internet using ngrok.", - ) - server_start_parser.add_argument( - "--ngrok-authtoken", - default=os.getenv("NGROK_AUTHTOKEN"), - help="The ngrok authtoken to use (visible in the ngrok dashboard)." - " If not provided, ngrok server session length will be restricted.", - ) server_start_parser.add_argument( "--stage", default="prod", @@ -421,13 +267,20 @@ def main() -> None: " LANGSMITH_LICENSE_KEY environment variable. If neither are provided," " the Langsmith application will not spin up.", ) + server_start_parser.add_argument( + "--version", + default="latest", + help="The LangSmith version to use for LangSmith. Defaults to latest." + " We recommend pegging this to the latest static version available at" + " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" + " if you are using Langsmith in production.", + ) server_start_parser.set_defaults( func=lambda args: server_command.start( - expose=args.expose, - auth_token=args.ngrok_authtoken, stage=args.stage, openai_api_key=args.openai_api_key, langsmith_license_key=args.langsmith_license_key, + version=args.version, ) ) @@ -452,8 +305,16 @@ def main() -> None: choices=["prod", "dev", "beta"], help="Which stage of LangSmith images to pull.", ) + server_pull_parser.add_argument( + "--version", + default="latest", + help="The LangSmith version to use for LangSmith. Defaults to latest." + " We recommend pegging this to the latest static version available at" + " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" + " if you are using Langsmith in production.", + ) server_pull_parser.set_defaults( - func=lambda args: server_command.pull(stage=args.stage) + func=lambda args: server_command.pull(stage=args.stage, version=args.version) ) server_logs_parser = subparsers.add_parser( "logs", description="Show the LangSmith server logs." diff --git a/python/tests/unit_tests/cli/test_main.py b/python/tests/unit_tests/cli/test_main.py index 55d5fe26b..98150b325 100644 --- a/python/tests/unit_tests/cli/test_main.py +++ b/python/tests/unit_tests/cli/test_main.py @@ -1,22 +1 @@ """Test utilities in the LangSmith server.""" -from langsmith.cli.main import _dumps_yaml - - -def test__dumps_yaml() -> None: - d = { - "region": "us", - "tunnels": {"langchain": {"addr": "langchain-backend:8000", "proto": "http"}}, - "version": "2", - } - expected = """region: us -tunnels: - langchain: - addr: langchain-backend:8000 - proto: http -version: 2""" - result = _dumps_yaml(d) - assert result == expected - expected += "\nauthtoken: 123" - d["authtoken"] = "123" - result = _dumps_yaml(d) - assert result == expected From 2fe6c026dca7832938fa557fb1c0b8f83cba7f6f Mon Sep 17 00:00:00 2001 From: infra Date: Wed, 13 Dec 2023 18:27:31 -0800 Subject: [PATCH 2/4] format --- js/src/cli/main.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/js/src/cli/main.ts b/js/src/cli/main.ts index 68ebe1a31..53ca0daa4 100644 --- a/js/src/cli/main.ts +++ b/js/src/cli/main.ts @@ -115,14 +115,13 @@ class SmithCommand { return new SmithCommand({ dockerComposeCommand }); } - async pull({ stage = "prod", version = "latest" }) { + async pull({ stage = "prod", version = "latest" }) { if (stage === "dev") { setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "dev-"); } else if (stage === "beta") { setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "rc-"); } - setEnvironmentVariable("_LANGSMITH_IMAGE_VERSION", version) - + setEnvironmentVariable("_LANGSMITH_IMAGE_VERSION", version); const command = [ ...this.dockerComposeCommand, @@ -223,10 +222,10 @@ const startCommand = new Command("start") ) .option( "--version ", -"The LangSmith version to use for LangSmith. Defaults to latest." + - " We recommend pegging this to the latest static version available at" + - " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" + - " if you are using Langsmith in production." + "The LangSmith version to use for LangSmith. Defaults to latest." + + " We recommend pegging this to the latest static version available at" + + " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" + + " if you are using Langsmith in production." ) .action(async (args) => { const smith = await SmithCommand.create(); @@ -255,10 +254,10 @@ const pullCommand = new Command("pull") ) .option( "--version ", -"The LangSmith version to use for LangSmith. Defaults to latest." + - " We recommend pegging this to the latest static version available at" + - " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" + - " if you are using Langsmith in production." + "The LangSmith version to use for LangSmith. Defaults to latest." + + " We recommend pegging this to the latest static version available at" + + " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" + + " if you are using Langsmith in production." ) .action(async (args) => { const smith = await SmithCommand.create(); From 8bdb5e0bf1a7653e4464749fd8e2f00a6a060b4d Mon Sep 17 00:00:00 2001 From: infra Date: Wed, 13 Dec 2023 18:30:15 -0800 Subject: [PATCH 3/4] format --- python/langsmith/cli/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/langsmith/cli/main.py b/python/langsmith/cli/main.py index a60a7c024..11878ec5a 100644 --- a/python/langsmith/cli/main.py +++ b/python/langsmith/cli/main.py @@ -162,7 +162,7 @@ def stop(self, clear_volumes: bool = False) -> None: *self.docker_compose_command, "-f", str(self.docker_compose_file), - "down" + "down", ] if clear_volumes: confirm = input( From 6f29c22eeaf3ccccfb8e1933b3bd53d3a7986a0a Mon Sep 17 00:00:00 2001 From: infra Date: Wed, 13 Dec 2023 18:45:07 -0800 Subject: [PATCH 4/4] Update versions --- js/package.json | 2 +- python/pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/package.json b/js/package.json index 3a132b593..0e9f4c2f1 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "langsmith", - "version": "0.0.49", + "version": "0.0.50", "description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.", "files": [ "dist/", diff --git a/python/pyproject.toml b/python/pyproject.toml index 2b222d7f6..6351aaf15 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langsmith" -version = "0.0.69" +version = "0.0.70" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." authors = ["LangChain "] license = "MIT"