diff --git a/js/package.json b/js/package.json index d54af9b47..45a05380e 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "langsmith", - "version": "0.1.60", + "version": "0.1.61", "description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.", "packageManager": "yarn@1.22.19", "files": [ diff --git a/js/src/index.ts b/js/src/index.ts index d77c8b7d1..96d782360 100644 --- a/js/src/index.ts +++ b/js/src/index.ts @@ -14,4 +14,4 @@ export { RunTree, type RunTreeConfig } from "./run_trees.js"; export { overrideFetchImplementation } from "./singletons/fetch.js"; // Update using yarn bump-version -export const __version__ = "0.1.60"; +export const __version__ = "0.1.61"; diff --git a/js/src/run_trees.ts b/js/src/run_trees.ts index 64cc7fb2b..5cb2aea97 100644 --- a/js/src/run_trees.ts +++ b/js/src/run_trees.ts @@ -356,36 +356,44 @@ export class RunTree implements BaseRun { } async postRun(excludeChildRuns = true): Promise { - const runtimeEnv = await getRuntimeEnvironment(); - const runCreate = await this._convertToCreate(this, runtimeEnv, true); - await this.client.createRun(runCreate); - - if (!excludeChildRuns) { - warnOnce( - "Posting with excludeChildRuns=false is deprecated and will be removed in a future version." - ); - for (const childRun of this.child_runs) { - await childRun.postRun(false); + try { + const runtimeEnv = await getRuntimeEnvironment(); + const runCreate = await this._convertToCreate(this, runtimeEnv, true); + await this.client.createRun(runCreate); + + if (!excludeChildRuns) { + warnOnce( + "Posting with excludeChildRuns=false is deprecated and will be removed in a future version." + ); + for (const childRun of this.child_runs) { + await childRun.postRun(false); + } } + } catch (error) { + console.error(`Error in postRun for run ${this.id}:`, error); } } async patchRun(): Promise { - const runUpdate: RunUpdate = { - end_time: this.end_time, - error: this.error, - inputs: this.inputs, - outputs: this.outputs, - parent_run_id: this.parent_run?.id, - reference_example_id: this.reference_example_id, - extra: this.extra, - events: this.events, - dotted_order: this.dotted_order, - trace_id: this.trace_id, - tags: this.tags, - }; - - await this.client.updateRun(this.id, runUpdate); + try { + const runUpdate: RunUpdate = { + end_time: this.end_time, + error: this.error, + inputs: this.inputs, + outputs: this.outputs, + parent_run_id: this.parent_run?.id, + reference_example_id: this.reference_example_id, + extra: this.extra, + events: this.events, + dotted_order: this.dotted_order, + trace_id: this.trace_id, + tags: this.tags, + }; + + await this.client.updateRun(this.id, runUpdate); + } catch (error) { + console.error(`Error in patchRun for run ${this.id}`, error); + } } toJSON() { diff --git a/js/src/tests/traceable.test.ts b/js/src/tests/traceable.test.ts index 9720701d1..ea8c009e3 100644 --- a/js/src/tests/traceable.test.ts +++ b/js/src/tests/traceable.test.ts @@ -1031,3 +1031,25 @@ test("argsConfigPath", async () => { }, }); }); + +test("traceable continues execution when client throws error", async () => { + const errorClient = { + createRun: jest.fn().mockRejectedValue(new Error("Client error") as never), + updateRun: jest.fn().mockRejectedValue(new Error("Client error") as never), + }; + + const tracedFunction = traceable( + async (value: number): Promise => value * 2, + { + client: errorClient as unknown as Client, + name: "errorTest", + tracingEnabled: true, + } + ); + + const result = await tracedFunction(5); + + expect(result).toBe(10); + expect(errorClient.createRun).toHaveBeenCalled(); + expect(errorClient.updateRun).toHaveBeenCalled(); +}); diff --git a/js/src/traceable.ts b/js/src/traceable.ts index dc43af0d3..aa8137c1a 100644 --- a/js/src/traceable.ts +++ b/js/src/traceable.ts @@ -617,20 +617,24 @@ export function traceable any>( if (isGenerator(wrappedFunc) && isIteratorLike(rawOutput)) { const chunks = gatherAll(rawOutput); - await currentRunTree?.end( - handleRunOutputs( - await handleChunks( - chunks.reduce((memo, { value, done }) => { - if (!done || typeof value !== "undefined") { - memo.push(value); - } - - return memo; - }, []) + try { + await currentRunTree?.end( + handleRunOutputs( + await handleChunks( + chunks.reduce((memo, { value, done }) => { + if (!done || typeof value !== "undefined") { + memo.push(value); + } + + return memo; + }, []) + ) ) - ) - ); - await handleEnd(); + ); + await handleEnd(); + } catch (e) { + console.error("Error occurred during handleEnd:", e); + } return (function* () { for (const ret of chunks) { diff --git a/python/langsmith/cli/.env.example b/python/langsmith/cli/.env.example index 87a978f1c..732fbd95b 100644 --- a/python/langsmith/cli/.env.example +++ b/python/langsmith/cli/.env.example @@ -1,5 +1,5 @@ # Don't change this file. Instead, copy it to .env and change the values there. The default values will work out of the box as long as you provide your license key. -_LANGSMITH_IMAGE_VERSION=0.7.7 # Change to the desired Langsmith image version +_LANGSMITH_IMAGE_VERSION=0.7.39 # Change to the desired Langsmith image version LANGSMITH_LICENSE_KEY=your-license-key # Change to your Langsmith license key AUTH_TYPE=none # Set to oauth if you want to use OAuth2.0. Set to mixed for basic auth. OAUTH_CLIENT_ID=your-client-id # Required if AUTH_TYPE=oauth @@ -18,6 +18,8 @@ CLICKHOUSE_TLS=false # Change to true if you are using TLS to connect to Clickho CLICKHOUSE_PASSWORD=password # Change to your Clickhouse password if needed CLICKHOUSE_NATIVE_PORT=9000 # Change to your Clickhouse native port if needed ORG_CREATION_DISABLED=false # Set to true if you want to disable org creation +WORKSPACE_SCOPE_ORG_INVITES_ENABLED=false # Set to true if you want to disable workspace scope org invites +PERSONAL_ORGS_DISABLED=false # Set to true if you want to disable personal orgs TTL_ENABLED=true # Set to true if you want to enable TTL for your data SHORT_LIVED_TTL_SECONDS=1209600 # Set to your desired TTL for short-lived traces. Default is 14 days LONG_LIVED_TTL_SECONDS=34560000 # Set to your desired TTL for long-lived traces. Default is 400 days diff --git a/python/langsmith/cli/docker-compose.yaml b/python/langsmith/cli/docker-compose.yaml index 2d4a8b4e9..71b36926a 100644 --- a/python/langsmith/cli/docker-compose.yaml +++ b/python/langsmith/cli/docker-compose.yaml @@ -1,11 +1,11 @@ version: "4" services: langchain-playground: - image: langchain/langsmith-playground:${_LANGSMITH_IMAGE_VERSION:-0.7.7} + image: langchain/langsmith-playground:${_LANGSMITH_IMAGE_VERSION:-0.7.39} ports: - 3001:3001 langchain-frontend: - image: langchain/langsmith-frontend:${_LANGSMITH_IMAGE_VERSION:-0.7.7} + image: langchain/langsmith-frontend:${_LANGSMITH_IMAGE_VERSION:-0.7.39} environment: - VITE_BACKEND_AUTH_TYPE=${AUTH_TYPE:-none} - VITE_OAUTH_CLIENT_ID=${OAUTH_CLIENT_ID} @@ -16,7 +16,7 @@ services: - langchain-backend - langchain-playground langchain-backend: - image: langchain/langsmith-backend:${_LANGSMITH_IMAGE_VERSION:-0.7.7} + image: langchain/langsmith-backend:${_LANGSMITH_IMAGE_VERSION:-0.7.39} environment: - PORT=1984 - LANGCHAIN_ENV=local_docker @@ -64,7 +64,7 @@ services: condition: service_completed_successfully restart: always langchain-platform-backend: - image: langchain/langsmith-go-backend:${_LANGSMITH_IMAGE_VERSION:-0.7.7} + image: langchain/langsmith-go-backend:${_LANGSMITH_IMAGE_VERSION:-0.7.39} environment: - PORT=1986 - LANGCHAIN_ENV=local_docker @@ -93,7 +93,7 @@ services: condition: service_completed_successfully restart: always langchain-queue: - image: langchain/langsmith-backend:${_LANGSMITH_IMAGE_VERSION:-0.7.7} + image: langchain/langsmith-backend:${_LANGSMITH_IMAGE_VERSION:-0.7.39} environment: - LANGCHAIN_ENV=local_docker - GO_ENDPOINT=http://langchain-platform-backend:1986 @@ -168,6 +168,12 @@ services: - 63791:6379 volumes: - langchain-redis-data:/data + command: + [ + "redis-server", + "--requirepass", + "password" + ] healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 2s @@ -193,7 +199,7 @@ services: timeout: 2s retries: 30 clickhouse-setup: - image: langchain/langsmith-backend:${_LANGSMITH_IMAGE_VERSION:-0.7.7} + image: langchain/langsmith-backend:${_LANGSMITH_IMAGE_VERSION:-0.7.39} depends_on: langchain-clickhouse: condition: service_healthy @@ -212,7 +218,7 @@ services: "scripts/wait_for_clickhouse_and_migrate.sh" ] postgres-setup: - image: langchain/langsmith-backend:${_LANGSMITH_IMAGE_VERSION:-0.7.7} + image: langchain/langsmith-backend:${_LANGSMITH_IMAGE_VERSION:-0.7.39} depends_on: langchain-db: condition: service_healthy diff --git a/python/langsmith/client.py b/python/langsmith/client.py index 66081653e..6df0f9004 100644 --- a/python/langsmith/client.py +++ b/python/langsmith/client.py @@ -1930,8 +1930,10 @@ def get_run_url( str The URL for the run. """ - if hasattr(run, "session_id") and run.session_id is not None: - session_id = run.session_id + if session_id := getattr(run, "session_id", None): + pass + elif session_name := getattr(run, "session_name", None): + session_id = self.read_project(project_name=session_name).id elif project_id is not None: session_id = project_id elif project_name is not None: @@ -5269,9 +5271,15 @@ def pull_prompt_commit( owner, prompt_name, commit_hash = ls_utils.parse_prompt_identifier( prompt_identifier ) - use_optimization = ls_utils.is_version_greater_or_equal( - self.info.version, "0.5.23" - ) + try: + use_optimization = ls_utils.is_version_greater_or_equal( + self.info.version, "0.5.23" + ) + except ValueError: + logger.exception( + "Failed to parse LangSmith API version. Defaulting to using optimization." + ) + use_optimization = True if not use_optimization and commit_hash == "latest": latest_commit_hash = self._get_latest_commit_hash(f"{owner}/{prompt_name}") @@ -5320,7 +5328,7 @@ def list_prompt_commits( owner, prompt_name, _ = ls_utils.parse_prompt_identifier(prompt_identifier) params = { - "limit": limit if limit is not None else 100, + "limit": min(100, limit) if limit is not None else limit, "offset": offset, "include_model": include_model, } @@ -5339,12 +5347,12 @@ def list_prompt_commits( if not items: break for it in items: - i += 1 + if limit is not None and i >= limit: + return # Stop iteration if we've reached the limit yield ls_schemas.ListedPromptCommit( **{"owner": owner, "repo": prompt_name, **it} ) - if limit is not None and i >= limit: - break + i += 1 offset += len(items) if offset >= total: diff --git a/python/pyproject.toml b/python/pyproject.toml index 36dd36c54..9bd0ce39f 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langsmith" -version = "0.1.128" +version = "0.1.129" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." authors = ["LangChain "] license = "MIT"